1 2// ******* Repeater MANAGER ******** // 3$axure.internal(function($ax) { 4 var _repeaterManager = {}; 5 $ax.repeater = _repeaterManager; 6 7 //This is a mapping of current editItems 8 var repeaterToEditItems = {}; 9 //This is a mapping of current filters 10 var repeaterToFilters = {}; 11 // This is a mapping of current sorts 12 var repeaterToSorts = {}; 13 // This is a mapping of repeater page info 14 var repeaterToPageInfo = {}; 15 16 //Hopefully this can be simplified, but for now I think 3 are needed. 17 //This is the data set that is owned by this repeater. The repeater may or may not reference this data set, and others can reference it. 18 var repeaterToLocalDataSet = {}; 19 //This is the data set referenced by the repeater. It is not a copy of the local data set, but a reference to a local data set (or eventually a global data set could be referenced). 20 var repeaterToCurrentDataSet = {}; 21 //This is a copy of the current data set, that is replaced whenever a set or refresh is done. 22 var repeaterToActiveDataSet = {}; 23 var _loadRepeaters = function() { 24 $ax(function(obj) { 25 return $ax.public.fn.IsRepeater(obj.type); 26 }).each(function(obj, repeaterId) { 27 repeaterToLocalDataSet[repeaterId] = $ax.deepCopy(obj.data); 28 repeaterToLocalDataSet[repeaterId].props = obj.dataProps; 29 repeaterToEditItems[repeaterId] = []; 30 31 _initPageInfo(obj, repeaterId); 32 33 _setRepeaterDataSet(repeaterId, repeaterId); 34 var initialItemIds = obj.repeaterPropMap.itemIds; 35 for (var i = 0; i < initialItemIds.length; i++) $ax.addItemIdToRepeater(initialItemIds[i], repeaterId); 36 $ax.visibility.initRepeater(repeaterId); 37 }); 38 }; 39 _repeaterManager.load = _loadRepeaters; 40 41 var _loaded = {}; 42 var _initRepeaters = function() { 43 $ax(function(obj, repeaterId) { 44 return $ax.public.fn.IsRepeater(obj.type) && !_loaded[repeaterId]; 45 }).each(function(obj, repeaterId) { 46 _refreshRepeater(repeaterId, undefined, true); 47 // Fix selected and default if necessary 48 var states = obj.evaluatedStates; 49 for(var i = 0; i < states.length; i++) { 50 var state = states[i]; 51 52 $ax.style.SetWidgetEnabled(state.id, true); // So selected will take place. If disabled, selected wouldn't happen. 53 $ax.style.SetWidgetSelected(state.id, state.selected); 54 $ax.style.SetWidgetEnabled(state.id, !state.disabled); 55 } 56 }); 57 }; 58 _repeaterManager.initRefresh = _initRepeaters; 59 60 var repeatersHaveNewDataSet = []; 61 var _setRepeaterDataSet = function(repeaterId, dataSetId) { 62 //TODO: No idea about how global data sets will be handled... 63 repeaterToCurrentDataSet[repeaterId] = repeaterToLocalDataSet[dataSetId]; 64 repeaterToActiveDataSet[repeaterId] = getActiveDataSet(repeaterId); 65 repeaterToFilters[repeaterId] = []; 66 repeaterToSorts[repeaterId] = []; 67 68 69 // Not using this currently 70 // if(repeatersHaveNewDataSet.indexOf(repeaterId) == -1) repeatersHaveNewDataSet[repeatersHaveNewDataSet.length] = repeaterId; 71 }; 72 _repeaterManager.setDataSet = _setRepeaterDataSet; 73 74 var _refreshRepeater = function(repeaterId, eventInfo, itemsPregen) { 75 // Don't show if you have a parent rdos thats limboed. 76 var rdoPath = $ax.getPathFromScriptId(repeaterId); 77 // Check each parent rdo through appropriate views to see if you are limboed 78 while (rdoPath.length > 0) { 79 if(!$ax.getScriptIdFromPath(rdoPath)) { 80 removeItems(repeaterId); 81 return; 82 } 83 84 $ax.splice(rdoPath, rdoPath.length - 1, 1); 85 } 86 87 _loaded[repeaterId] = true; 88 $ax.action.refreshStart(repeaterId); 89 $ax.style.ClearCacheForRepeater(repeaterId); 90 91 if($ax.visibility.limboIds[repeaterId]) { 92 removeItems(repeaterId); 93 $ax.dynamicPanelManager.fitParentPanel(repeaterId); 94 return; 95 } 96 97 // Remove delete map if there is one at this point 98 if(eventInfo && eventInfo.repeaterDeleteMap) delete eventInfo.repeaterDeleteMap[repeaterId]; 99 var path = $ax.getPathFromScriptId(repeaterId); 100 path.pop(); 101 102 if(eventInfo) { 103 eventInfo = $ax.eventCopy(eventInfo); 104 } 105 106 var obj = $ax.getObjectFromScriptId(repeaterId); 107 var propMap = obj.repeaterPropMap; 108 109 //If there is no wrap, then set it to be above the number of rows 110 var viewId = $ax.adaptive.currentViewId || ''; 111 var wrap = _getAdaptiveProp(propMap, 'wrap', viewId); 112 var vertical = _getAdaptiveProp(propMap, 'vertical', viewId); 113 var offset = propMap[viewId]; 114
115 // Right now pregen only works for default adaptive view 116 if(viewId) itemsPregen = false; 117 var orderedIds = []; 118 if(itemsPregen) { 119 var repeaterChildren = $jobj(repeaterId).children(); 120 // Start at 1 to skip script div child 121 for(var i = 1; i < repeaterChildren.length; i++) { 122 orderedIds.push(_getItemIdFromElementId($(repeaterChildren[i]).attr('id'))); 123 } 124 } else orderedIds = getOrderedIds(repeaterId, eventInfo); 125 var ids = []; 126 var background = _getAdaptiveProp(propMap, 'backColor', viewId); 127 var hasAltColor = _getAdaptiveProp(propMap, 'hasAltColor', viewId); 128 var altColor = hasAltColor ? _getAdaptiveProp(propMap, 'altColor', viewId) : undefined; 129 var useAlt = false; 130 131 if(itemsPregen) { 132 var start = 0; 133 var end = orderedIds.length; 134 } else { 135 var bounds = _getVisibleDataBounds(repeaterToPageInfo[repeaterId], itemsPregen ? obj.data.length : orderedIds.length); 136 start = bounds[0]; 137 end = bounds[1]; 138 } 139 140 var preevalMap = {}; 141 if(itemsPregen) { 142 var templateIds = [repeaterId]; 143 var processScriptIds = function (full, prop, id) { 144 if(id.indexOf('_') <= 0 && id.indexOf('p') == -1) templateIds.push('u' + id); 145 }; 146 $('#' + repeaterId + '_script').html().replace(/(id|for)="?u([0-9]+(p([0-9]){3})?(_[_a-z0-9]*)?)"?/g, processScriptIds); 147 for(var i = 0; i < templateIds.length; i++) { 148 for(var j = 0; j < orderedIds.length; j++) { 149 ids.push(_createElementId(templateIds[i], orderedIds[j])); 150 } 151 } 152 153 for(var pos = start; pos < end; pos++) { 154 var itemId = orderedIds[pos]; 155 itemElementId = _createElementId(repeaterId, itemId); 156 var jobj = $jobj(itemElementId); 157 var preeval = jobj.hasClass('preeval'); 158 for(var i = 0; i < templateIds.length; i++) $ax.initializeObjectEvents($ax('#' + _createElementId(templateIds[i], itemId)), !preeval); 159 if(preeval) { 160 preevalMap[itemId] = true; 161 jobj.removeClass('preeval'); 162 } 163 } 164 } else { 165 var html = $('#' + repeaterId + '_script').html();
166 // var container = $('<div></div>'); 167 // container.html(html); 168 // container.attr('id', '' + repeaterId + '_container'); 169 // container.css({ position: 'absolute' }); 170 // container.offset({ left: -obj.x, top: -obj.y }); 171 172 var div = $('<div></div>'); 173 div.html(html); 174 div.find('.' + $ax.visibility.HIDDEN_CLASS).removeClass($ax.visibility.HIDDEN_CLASS); 175 div.find('.' + $ax.visibility.UNPLACED_CLASS).removeClass($ax.visibility.UNPLACED_CLASS); 176 177 var paddingTop = _getAdaptiveProp(propMap, 'paddingTop', viewId); 178 var paddingLeft = _getAdaptiveProp(propMap, 'paddingLeft', viewId); 179 var paddingY = paddingTop + _getAdaptiveProp(propMap, 'paddingBottom', viewId); 180 var paddingX = paddingLeft + _getAdaptiveProp(propMap, 'paddingRight', viewId); 181 182 var spacingX = _getAdaptiveProp(propMap, 'horizontalSpacing', viewId); 183 var xOffset = offset.width + spacingX; 184 var spacingY = _getAdaptiveProp(propMap, 'verticalSpacing', viewId); 185 var yOffset = offset.height + spacingY; 186 div.css({ 187 width: offset.width, 188 height: offset.height 189 }); 190 191 _applyColorCss(background, div); 192 var altDiv = div; 193 if(hasAltColor) altDiv = _applyColorCss(altColor, div.clone()); 194 195 // Hide repeater, if shown, while updating. 196 var shown = $ax.visibility.IsIdVisible(repeaterId); 197 if(shown) document.getElementById(repeaterId).style.visibility = 'hidden'; 198 199 200 var resized = $ax.getItemIdsForRepeater(repeaterId).length != (end - start) || 201 (repeaterSizes[repeaterId] && repeaterSizes[repeaterId].resized); 202 203 //clean up old items as late as possible 204 removeItems(repeaterId); 205 resetItemSizes(repeaterId, offset, bounds, orderedIds, vertical, wrap); 206 207 var i = 0; 208 var top = paddingTop; 209 var left = paddingLeft; 210 for(pos = start; pos < end; pos++) { 211 itemId = orderedIds[pos]; 212 213 var itemElementId = _createElementId(repeaterId, itemId); 214 $ax.addItemIdToRepeater(itemId, repeaterId); 215 216 ids.push(itemElementId); 217 var processId = function(full, prop, id) { 218 var elementId = _createElementId('u' + id, itemId); 219 //If there is a suffix (ex. _img), then don't push the id. 220 if (id.indexOf('_') <= 0 && id.indexOf('p') == -1) ids.push(elementId); 221 return prop + '="' + elementId + '"'; 222 }; 223 224 var copy = (useAlt ? altDiv : div).clone(); 225 useAlt = !useAlt; 226 copy.attr('id', itemElementId); 227 copy.html(div.html().replace(/(id|for)="?u([0-9]+(p([0-9]){3})?(_[_a-z0-9]*)?)"?/g, processId)); 228 229 copy.css({ 230 'position': 'absolute', 231 'top': top + 'px', 232 'left': left + 'px', 233 'width': obj.width + 'px', 234 'height': obj.height + 'px' 235 }); 236 $('#' + repeaterId).append(copy); 237 238 i++; 239 if(wrap != -1 && i % wrap == 0) { 240 if(vertical) { 241 top = paddingTop; 242 left += xOffset; 243 } else { 244 left = paddingLeft; 245 top += yOffset; 246 } 247 } else if (vertical) top += yOffset; 248 else left += xOffset; 249 } 250 251 var shownCount = end - start; 252 var repeaterSize = { width: paddingX, height: paddingY}; 253 if(shownCount > 0) { 254 var primaryCount = wrap == -1 ? shownCount : Math.min(shownCount, wrap); 255 var secondaryCount = wrap == -1 ? 1 : Math.ceil(shownCount / wrap); 256 257 var widthCount = vertical ? secondaryCount : primaryCount; 258 var heightCount = vertical ? primaryCount : secondaryCount; 259 repeaterSize.width += offset.width + (widthCount - 1) * xOffset; 260 repeaterSize.height += offset.height + (heightCount - 1) * yOffset; 261 } 262 var borderWidth = $ax.getNumFromPx($jobj(repeaterId).css('border-width')) || 0; 263 repeaterSize.width += borderWidth * 2; 264 repeaterSize.height += borderWidth * 2; 265 $jobj(repeaterId).css(repeaterSize); 266 267 for(var i = 0; i < ids.length; i++) $ax.initializeObjectEvents($ax('#' + ids[i]), true); 268 } 269 270 var query = _getItemQuery(repeaterId);
271 if(viewId) $ax.adaptive.applyView(viewId, query); 272 else $ax.visibility.resetLimboAndHiddenToDefaults(_getItemQuery(repeaterId, preevalMap)); 273// else { 274// var limbo = {}; 275// var hidden = {}; 276// query.each(function(diagramObject, elementId) { 277// // sigh, javascript. we need the === here because undefined means not overriden 278//// var visible = diagramObject.style.visible; 279// var visible = $ax.visibility.IsIdVisible(elementId); 280// if (visible === false) hidden[elementId] = true; 281// //todo: **mas** check if the limboed widgets are hidden by default by the generator 282// if(diagramObject.style.limbo) limbo[elementId] = true; 283// }); 284// $ax.visibility.addLimboAndHiddenIds(limbo, hidden, query); 285// $ax.dynamicPanelManager.updatePercentPanelCache(query); 286// } 287 $ax.annotation.InitializeAnnotations(query); 288 289 for(var index = 0; index < ids.length; index++) { 290 var id = ids[index]; 291 var childObj = $obj(id); 292 var childJobj = $jobj(id); 293 var childItemId = _getItemIdFromElementId(id); 294 if (obj.repeaterPropMap.isolateRadio && $ax.public.fn.IsRadioButton(childObj.type)) { 295 var input = $jobj(_applySuffixToElementId(id, '_input')); 296 input.attr('name', _createElementId(input.attr('name'), childItemId)); 297 if($ax.ieColorManager) $ax.ieColorManager.applyBackground($ax('#' + id)); 298 } 299 if(obj.repeaterPropMap.isolateSelection && childJobj.attr('selectiongroup')) { 300 childJobj.attr('selectiongroup', _createElementId(childJobj.attr('selectiongroup'), childItemId)); 301 } 302 // Had to move this earlier, because it sets up cursor: pointer on inline links, 303 // but must be done before style cached when adaptive view is set. 304 //$ax.initializeObjectEvents($ax('#' + id)); 305 $ax.dynamicPanelManager.initFitPanels($ax('#' + id)); 306 $ax.style.initializeObjectTextAlignment($ax('#' + id)); 307 $ax.applyHighlight($ax('#' + id), true); 308 } 309 310 //$ax.event.raiseSyntheticEvent(itemElementId, 'onLoad', true); 311 //$ax.loadDynamicPanelsAndMasters(obj.objects, path, itemId); 312 313 // Now load 314 for(pos = start; pos < end; pos++) { 315 itemId = orderedIds[pos]; 316 itemElementId = _createElementId(repeaterId, itemId); 317 if(!preevalMap[orderedIds[pos]]) $ax.event.raiseSyntheticEvent(itemElementId, 'onItemLoad', true); 318 $ax.loadDynamicPanelsAndMasters(obj.objects, path, itemId); 319 } 320 321 // Reshow repeater if it was originally shown (load is complete by now) 322 if(shown && !itemsPregen) document.getElementById(repeaterId).style.visibility = 'visible'; 323 324 $ax.dynamicPanelManager.fitParentPanel(repeaterId); 325 326 // Right now we assume only one refresh at a time. If we can manually trigger refreshes, that may possibly change. 327 $ax.action.refreshEnd(); 328 }; 329 _repeaterManager.refreshRepeater = _refreshRepeater; 330 331 var _getItemQuery = function(repeaterId, preevalMap) { 332 var query = $ax(function (diagramObject, elementId) { 333 // Also need to check that this in not preeval 334 if(preevalMap) { 335 var itemId = _getItemIdFromElementId(elementId); 336 if(preevalMap[itemId]) return false; 337 } 338 339 // All objects with the repeater as their parent, except the repeater itself. 340 var scriptId = _getScriptIdFromElementId(elementId); 341 return $ax.getParentRepeaterFromScriptId(scriptId) == repeaterId && scriptId != repeaterId; 342 }); 343 344 return query; 345 } 346 347 _repeaterManager.refreshAllRepeaters = function() { 348 $ax('*').each(function(diagramObject, elementId) { 349 if (!$ax.public.fn.IsRepeater(diagramObject.type)) return; 350 351 _initPageInfo(diagramObject, elementId); 352 _refreshRepeater(elementId, $ax.getEventInfoFromEvent($ax.getjBrowserEvent())); 353 }); 354 }; 355 356 _repeaterManager.refreshRepeaters = function(ids, eventInfo) { 357 for(var i = 0; i < ids.length; i++) _refreshRepeater(ids[i], eventInfo); 358 }; 359 360 var _initPageInfo = function(obj, elementId) { 361 var pageInfo = {}; 362 var map = obj.repeaterPropMap; 363 364 var currentViewId = $ax.adaptive.currentViewId || ''; 365 var itemsPerPage = _getAdaptiveProp(map, 'itemsPerPage', currentViewId); 366 if(itemsPerPage == -1) pageInfo.noLimit = true; 367 else { 368 pageInfo.itemsPerPage = itemsPerPage; 369 pageInfo.currPage = _getAdaptiveProp(map, 'currPage', currentViewId); 370 } 371 repeaterToPageInfo[elementId] = pageInfo; 372 }; 373 374 _repeaterManager.initialize = function() { 375 $ax(function (obj) { 376 return $ax.public.fn.IsRepeater(obj.type); 377 }).each(function (obj, repeaterId) { 378 _initPregen(repeaterId); 379 }); 380 } 381 382 var _initPregen = function(repeaterId) { 383 var obj = $ax.getObjectFromScriptId(repeaterId); 384 var propMap = obj.repeaterPropMap; 385 386 //If there is no wrap, then set it to be above the number of rows 387 var viewId = $ax.adaptive.currentViewId || ''; 388 var wrap = _getAdaptiveProp(propMap, 'wrap', viewId); 389 var vertical = _getAdaptiveProp(propMap, 'vertical', viewId); 390 391 var orderedIds = []; 392 var ids = []; 393 var background = _getAdaptiveProp(propMap, 'backColor', viewId); 394 var hasAltColor = _getAdaptiveProp(propMap, 'hasAltColor', viewId); 395 var altColor = hasAltColor ? _getAdaptiveProp(propMap, 'altColor', viewId) : undefined; 396 var useAlt = false; 397 398 var bounds = _getVisibleDataBounds(repeaterToPageInfo[repeaterId], obj.data.length); 399 var start = bounds[0]; 400 var end = bounds[1]; 401 402 // Starts empty 403 if(start == end) { 404 $ax.action.refreshEnd(repeaterId); 405 return; 406 } 407 var unprocessedBaseIds = $jobj($ax.repeater.createElementId(repeaterId, start + 1)).html().match(/(id|for)="?u([0-9]+)/g); 408 var baseIds = []; 409 if(unprocessedBaseIds) { 410 for(var i = 0; i < unprocessedBaseIds.length; i++) { 411 var val = unprocessedBaseIds[i].split('=')[1].substr(1); 412 if(baseIds.indexOf(val) == -1) baseIds.push(val); 413 } 414 } 415 416 for(var itemNum = start; itemNum < end; itemNum++) { 417 ids.push($ax.repeater.createElementId(repeaterId, itemNum + 1)); 418 for(i = 0; i < baseIds.length; i++) ids.push($ax.repeater.createElementId(baseIds[i], itemNum + 1)); 419 var itemId = itemNum + 1; 420 orderedIds[itemNum] = itemId; 421 422 var itemDiv = $jobj($ax.repeater.createElementId(repeaterId, itemNum + 1)); 423 _applyColorCss(useAlt ? altColor : background, itemDiv); 424 if(hasAltColor) useAlt = !useAlt; 425 } 426 427 resetItemSizes(repeaterId, undefined, bounds, orderedIds, vertical, wrap); 428 }; 429 430 var _applyColorCss = function(json, div) { 431 var args = json.r + ', ' + json.g + ', ' + json.b; 432 var background = json.a == 0 ? '' : json.a == 1 ? 'rgb(' + args + ')' : 'rgba(' + args + ', ' + json.a + ')'; 433 if($ax.ieColorManager && json.a != 0 && json.a != 1) { 434 var ieColor = $ax.ieColorManager.getColorFromArgb(json.a * 255, json.r, json.g, json.b, true); 435 if(ieColor) background = ieColor; 436 } 437 div.css('background-color', background); 438 return div; 439 }; 440 441 var _getAdaptiveProp = _repeaterManager.getAdaptiveProp = function(map, prop, viewId) { 442 var viewChain = $ax.adaptive.getAdaptiveIdChain(viewId); 443 for(var i = viewChain.length - 1; i >= 0; i--) { 444 viewId = viewChain[i]; 445 var viewProps = map[viewId]; 446 if(viewProps.hasOwnProperty(prop)) return viewProps[prop]; 447 } 448 449 var base = map['']; 450 if(base.hasOwnProperty(prop)) return base[prop]; 451 return map['default'][prop]; 452 }; 453 454 _repeaterManager.getItemCount = function(repeaterId) { 455 var data = repeaterToActiveDataSet[repeaterId].length; 456 var info = repeaterToPageInfo[repeaterId]; 457 if(!info.noLimit) { 458 var start = Math.min(data, info.itemsPerPage * info.currPage); 459 var end = Math.min(data, start + info.itemsPerPage); 460 data = end - start; 461 } 462 return data; 463 }; 464 465 _repeaterManager.setDisplayProps = function(obj, repeaterId, itemIndex) { 466 var data = repeaterToActiveDataSet[repeaterId]; 467 var info = repeaterToPageInfo[repeaterId]; 468 var start = 0; 469 var end = data.length; 470 if(!info.noLimit) { 471 start = Math.min(end, info.itemsPerPage * (info.currPage - 1)); 472 end = Math.min(end, start + info.itemsPerPage); 473 } 474 var count = end - start; 475 var index = -1; 476 for(var i = 0; i < count; i++) { 477 if(data[start + i].index == itemIndex) index = i + 1; 478 } 479 if(index == -1) return; 480 obj.index = index; 481 obj.isfirst = index == 1; 482 obj.islast = index == end - start; 483 obj.iseven = index % 2 == 0; 484 obj.isodd = index % 2 == 1;
485 }; 486 487 var _getVisibleDataBounds = function(pageInfo, count) { 488 var retval = [0, count]; 489 if(!pageInfo.noLimit) { 490 var end = pageInfo.itemsPerPage * pageInfo.currPage; 491 var start = end - pageInfo.itemsPerPage; 492 493 // If past the end, move to last page 494 if(start >= count) { 495 pageInfo.currPage = Math.floor((count - 1) / pageInfo.itemsPerPage) + 1; 496 if(pageInfo.currPage <= 0) pageInfo.currPage = 1; 497 498 end = pageInfo.itemsPerPage * pageInfo.currPage; 499 start = end - pageInfo.itemsPerPage; 500 } 501 end = Math.min(end, count); 502 retval[0] = start; 503 retval[1] = end; 504 } 505 return retval; 506 }; 507 508 _repeaterManager.getVisibleDataCount = function(repeaterId) { 509 var bounds = _getVisibleDataBounds(repeaterToPageInfo[repeaterId], repeaterToActiveDataSet[repeaterId].length); 510 return bounds[1] - bounds[0]; 511 }; 512 513 _repeaterManager.getDataCount = function(repeaterId) { 514 return repeaterToCurrentDataSet[repeaterId].length; 515 }; 516 517 var _getFilteredDataCount = _repeaterManager.getFilteredDataCount = function(repeaterId) { 518 return repeaterToActiveDataSet[repeaterId].length; 519 }; 520 521 _repeaterManager.getPageCount = function(repeaterId) { 522 var info = repeaterToPageInfo[repeaterId]; 523 return info.noLimit ? 1 : Math.ceil(_getFilteredDataCount(repeaterId) / info.itemsPerPage); 524 }; 525 526 _repeaterManager.getPageIndex = function(repeaterId) { 527 var info = repeaterToPageInfo[repeaterId]; 528 return info.noLimit ? 1 : info.currPage; 529 }; 530 531 var getActiveDataSet = function(repeaterId) { 532 var active = $ax.deepCopy(repeaterToCurrentDataSet[repeaterId]); 533 // Set up 1 indexing each item. 534 for(var i = 0; i < active.length; i++) active[i].index = i + 1; 535 return active; 536 }; 537 538 var getOrderedIds = function(repeaterId, eventInfo) { 539 var data = repeaterToActiveDataSet[repeaterId] = getActiveDataSet(repeaterId); 540 541 // Filter first so less to sort 542 applyFilter(repeaterId, data, eventInfo); 543 544 // Sort next 545 var sorts = repeaterToSorts[repeaterId] || []; 546 if(sorts.length != 0 && data.length > 1) { 547 // TODO: Make this generic and factor out if we want to use it elsewhere... 548 // Compare is a function that takes 2 arguments, and returns a number. A high number means the second should go first 549 // Otherwise the first stays first. 550 var mergesort = function(list, start, end, compare) { 551 var middle = Math.floor((start + end) / 2); 552 if(middle - start > 1) mergesort(list, start, middle, compare); 553 if(end - middle > 1) mergesort(list, middle, end, compare); 554 var index1 = start; 555 var index2 = middle; 556 var tempList = []; 557 while(index1 < middle && index2 < end) { 558 tempList[tempList.length] = list[compare(list[index1], list[index2]) > 0 ? index2++ : index1++]; 559 } 560 while(index1 < middle) tempList[tempList.length] = list[index1++]; 561 while(index2 < end) tempList[tempList.length] = list[index2++]; 562 563 // transfer from temp list to the real list. 564 for(var i = 0; i < tempList.length; i++) list[start + i] = tempList[i]; 565 }; 566 // Compare is the tie breaking function to us if necessary. 567 var getComparator = function(columnName, ascending, type, compare) { 568 // If this needs to be sped up, break up into several smaller functions conditioned off of type 569 return function(row1, row2) { 570 // If column undefined, no way to measure this, so call it a tie. 571 if(row1[columnName] === undefined || row2[columnName] === undefined) return 0; 572 573 var text1 = row1[columnName].text; 574 var text2 = row2[columnName].text; 575 576 // This means we are case insensitive, so lowercase everything to kill casing 577 if(type == 'Text') { 578 text1 = text1.toLowerCase(); 579 text2 = text2.toLowerCase(); 580 } 581 582 //If tied, go to tie breaker 583 if(text1 == text2) { 584 if(compare) return compare(row1, row2); 585 // Actually a tie. 586 return 0; 587 } 588 if(type == 'Text' || type == 'Text (Case Sensitive)') { 589 if(text1 < text2 ^ ascending) return 1; 590 else return -1; 591 } else if(type == 'Number') { 592 var num1 = Number(text1); 593 var num2 = Number(text2); 594 595 if(isNaN(num1) && isNaN(num2)) return 0; 596 if(isNaN(num1) || isNaN(num2)) return isNaN(num1) ? 1 : -1; 597 if(num1 < num2 ^ ascending) return 1; 598 else return -1; 599 } else if(type == 'Date - YYYY-MM-DD' || type == 'Date - MM/DD/YYYY') { 600 var func = type == 'Date - YYYY-MM-DD' ? getDate1 : getDate2; 601 var date1 = func(text1); 602 var date2 = func(text2); 603 if(!date1.valid && !date2.valid) return 0; 604 if(!date1.valid || !date2.valid) return date1.valid ? -1 : 1; 605 var diff = date2.year - date1.year; 606 if(diff == 0) diff = date2.month - date1.month; 607 if(diff == 0) diff = date2.day - date1.day; 608 if(diff == 0) return 0; 609 return diff > 0 ^ ascending ? 1 : -1; 610 } 611 console.log('unhandled sort type'); 612 return 0; 613 }; 614 }; 615 var compareFunc = null; 616 for(var i = 0; i < sorts.length; i++) compareFunc = getComparator(sorts[i].columnName, sorts[i].ascending, sorts[i].sortType, compareFunc); 617 618 mergesort(data, 0, data.length, compareFunc); 619 } 620 621 var ids = []; 622 for(i = 0; i < data.length; i++) ids[i] = data[i].index; 623 624 return ids; 625 }; 626 627 var getDate1 = function(text) { 628 var date = { valid: false }; 629 var sections = text.split('-'); 630 if(sections.length == 1) sections = text.split('/'); 631 if(sections.length != 3) return date; 632 date.year = Number(sections[0]); 633 date.month = Number(sections[1]); 634 date.day = Number(sections[2]); 635 date.valid = !isNaN(date.year); 636 date.valid &= !isNaN(date.month) && date.month > 0 && date.month <= 12; 637 date.valid &= !isNaN(date.day) && date.day > 0 && date.day <= daysPerMonth(date.month, date.year); 638 return date; 639 }; 640 641 var getDate2 = function(text) { 642 var date = { valid: false }; 643 var sections = text.split('-'); 644 if(sections.length == 1) sections = text.split('/'); 645 if(sections.length != 3) return date; 646 date.month = Number(sections[0]); 647 date.day = Number(sections[1]); 648 date.year = Number(sections[2]); 649 date.valid = !isNaN(date.year); 650 date.valid &= !isNaN(date.month) && date.month > 0 && date.month <= 12; 651 date.valid &= !isNaN(date.day) && date.day > 0 && date.day <= daysPerMonth(date.month, date.year); 652 return date; 653 }; 654 655 var daysPerMonth = function(month, year) {
656 if(month == 9 || month == 4 || month == 6 || month == 11) return 30; 657 if(month != 2) return 31; 658 659 if(year % 4 != 0) return 28; 660 if(year % 100 != 0) return 29; 661 return year % 400 == 0 ? 29 : 28; 662 }; 663 664 var applyFilter = function(repeaterId, data, eventInfo) { 665 var dataFiltered = []; 666 var filters = repeaterToFilters[repeaterId] || []; 667 if (filters.length != 0) { 668 var oldTarget = eventInfo.targetElement; 669 var oldSrc = eventInfo.srcElement; 670 var oldThis = eventInfo.thiswidget; 671 var oldItem = eventInfo.item; 672 673 outer: 674 for(var i = 1; i <= data.length; i++) { 675 for(var j = 0; j < filters.length; j++) { 676 eventInfo.targetElement = _createElementId(repeaterId, i); 677 eventInfo.srcElement = filters[j].thisId; 678 eventInfo.thiswidget = $ax.getWidgetInfo(eventInfo.srcElement); 679 eventInfo.item = $ax.getItemInfo(eventInfo.srcElement); 680 681 if($ax.expr.evaluateExpr(filters[j].filter, eventInfo) != 'true') continue outer; 682 } 683 dataFiltered[dataFiltered.length] = data[i - 1]; 684 } 685 686 for(i = 0; i < dataFiltered.length; i++) data[i] = dataFiltered[i]; 687 while(data.length > dataFiltered.length) data.pop(); 688 689 eventInfo.targetElement = oldTarget; 690 eventInfo.srcElement = oldSrc; 691 eventInfo.thiswidget = oldThis; 692 eventInfo.item = oldItem; 693 } 694 }; 695 696 var _addFilter = function(repeaterId, removeOtherFilters, label, filter, thisId) { 697 if(removeOtherFilters) _removeFilter(repeaterId); 698 699 var filterList = repeaterToFilters[repeaterId]; 700 if(!filterList) repeaterToFilters[repeaterId] = filterList = []; 701 702 var filterObj = { filter: filter, thisId: thisId }; 703 if(label) filterObj.label = label; 704 filterList[filterList.length] = filterObj; 705 }; 706 _repeaterManager.addFilter = _addFilter; 707 708 var _removeFilter = function(repeaterId, label) { 709 var filterList = repeaterToFilters[repeaterId]; 710 // If no list, nothing to remove 711 if(!filterList) return; 712 713 // If no label, remove everything 714 if(!label) { 715 repeaterToFilters[repeaterId] = []; 716 return; 717 } 718 719 for(var i = filterList.length - 1; i >= 0; i--) { 720 var filterObj = filterList[i]; 721 if(filterObj.label && filterObj.label == label) $ax.splice(filterList, i, 1); 722 } 723 }; 724 _repeaterManager.removeFilter = _removeFilter; 725 726 var _addSort = function(repeaterId, label, columnName, ascending, toggle, sortType) { 727 var sortList = repeaterToSorts[repeaterId]; 728 if(!sortList) repeaterToSorts[repeaterId] = sortList = []; 729 730 for(var i = 0; i < sortList.length; i++) { 731 if(columnName == sortList[i].columnName) { 732 var lastSortObj = $ax.splice(sortList, i, 1)[0]; 733 if(toggle) ascending = !lastSortObj.ascending; 734 break; 735 } 736 } 737 738 var sortObj = { columnName: columnName, ascending: ascending, sortType: sortType }; 739 740 if(label) sortObj.label = label; 741 sortList[sortList.length] = sortObj; 742 }; 743 _repeaterManager.addSort = _addSort; 744 745 var _removeSort = function(repeaterId, label) { 746 var sortList = repeaterToSorts[repeaterId]; 747 // If no list, nothing to remove 748 if(!sortList) return; 749 750 // If no label, remove everything 751 if(!label) { 752 repeaterToSorts[repeaterId] = []; 753 return; 754 } 755 756 for(var i = sortList.length - 1; i >= 0; i--) { 757 var sortObj = sortList[i]; 758 if(sortObj.label && sortObj.label == label) $ax.splice(sortList, i, 1); 759 } 760 }; 761 _repeaterManager.removeSort = _removeSort; 762 763 var _setRepeaterToPage = function(repeaterId, type, value, eventInfo) { 764 var pageInfo = repeaterToPageInfo[repeaterId]; 765 // page doesn't matter if there is no limit. 766 if(pageInfo.noLimit) return; 767 768 var dataSet = repeaterToActiveDataSet[repeaterId]; 769 if(!dataSet) dataSet = repeaterToCurrentDataSet[repeaterId]; 770 var lastPage = Math.max(1, Math.ceil(dataSet.length / pageInfo.itemsPerPage)); 771 772 if(type == 'Value') { 773 var val = Number($ax.expr.evaluateExpr(value, eventInfo)); 774 // if invalid, default to 1, otherwise, clamp the value 775 if(isNaN(val)) val = 1; 776 else if(val < 1) val = 1; 777 else if(val > lastPage) val = lastPage; 778 779 pageInfo.currPage = val; 780 } else if(type == 'Previous') { 781 if(pageInfo.currPage > 1) pageInfo.currPage--; 782 } else if(type == 'Next') { 783 if(pageInfo.currPage < lastPage) pageInfo.currPage++; 784 } else if(type == 'Last') { 785 pageInfo.currPage = lastPage; 786 } else { 787 console.log('Unknown type'); 788 } 789 }; 790 _repeaterManager.setRepeaterToPage = _setRepeaterToPage; 791 792 var _setNoItemLimit = function(repeaterId) { 793 var pageInfo = repeaterToPageInfo[repeaterId]; 794 delete pageInfo.currPage; 795 delete pageInfo.itemsPerPage; 796 pageInfo.noLimit = true; 797 }; 798 _repeaterManager.setNoItemLimit = _setNoItemLimit; 799 800 var _setItemLimit = function(repeaterId, value, eventInfo) { 801 var pageInfo = repeaterToPageInfo[repeaterId]; 802 803 if(pageInfo.noLimit) { 804 pageInfo.noLimit = false; 805 pageInfo.currPage = 1; 806 } 807 808 var oldTarget = eventInfo.targetElement; 809 eventInfo.targetElement = repeaterId; 810 var itemLimit = Number($ax.expr.evaluateExpr(value, eventInfo)); 811 eventInfo.targetElement = oldTarget; 812 if(isNaN(itemLimit)) itemLimit = 20; 813 else if(itemLimit < 1) itemLimit = 1; 814 pageInfo.itemsPerPage = itemLimit; 815 }; 816 _repeaterManager.setItemLimit = _setItemLimit; 817 818 var removeItems = function(repeaterId) { 819 var elementIds = $ax.getChildElementIdsForRepeater(repeaterId); 820 var itemId = $ax.getItemIdsForRepeater(repeaterId); 821 for(var i = 0; i < itemId.length; i++) $jobj(_createElementId(repeaterId, itemId[i])).remove(); 822 $ax.visibility.clearLimboAndHiddenIds(elementIds); 823 $ax.clearItemsForRepeater(repeaterId); 824 }; 825 826 var repeaterSizes = {}; 827 var resetItemSizes = function (repeaterId, itemSize, bounds, ids, vertical, wrap) { 828 var calcItem = !itemSize; 829 if(calcItem) itemSize = {}; 830 831 var repeaterMap = {}; 832 repeaterMap.vert = vertical; 833 var sizesMap = {}; 834 var sizes = []; 835 var currSizes = wrap == -1 ? sizes : []; 836 for(var i = 0; i + bounds[0] < bounds[1]; i++) { 837 var itemId = ids[i + bounds[0]];
838 if(calcItem) { 839 var itemJobj = $jobj(_createElementId(repeaterId, itemId)); 840 itemSize.width = $ax.getNumFromPx(itemJobj.css('width')); 841 itemSize.height = $ax.getNumFromPx(itemJobj.css('height')); 842 } 843 844 var size = { itemId: itemId, width: itemSize.width, height: itemSize.height }; 845 currSizes.push(size); 846 sizesMap[size.itemId] = size; 847 if(currSizes.length == wrap) { 848 sizes.push(currSizes); 849 currSizes = []; 850 } 851 } 852 if (wrap != -1 && currSizes.length > 0) sizes.push(currSizes); 853 repeaterMap.sizes = sizes; 854 repeaterMap.sizesMap = sizesMap; 855 repeaterSizes[repeaterId] = repeaterMap; 856 }; 857 858 _repeaterManager.getItemSize = function(repeaterId, itemId) { 859 var repeaterSize = repeaterSizes[repeaterId]; 860 if (!repeaterSize) return false; 861 return repeaterSize.sizesMap[itemId]; 862 } 863 864 _repeaterManager.setItemSize = function (repeaterId, itemId, width, height) { 865 var repeaterSize = repeaterSizes[repeaterId]; 866 if(!repeaterSize) return false; 867 var size = repeaterSize.sizesMap[itemId]; 868 var deltaX = width - size.width; 869 var deltaY = height - size.height; 870 if(!deltaX && !deltaY) return false; 871 872 repeaterSize.resized = true; 873 874 if(deltaX) _pushItems(repeaterId, itemId, deltaX, false, true); 875 if(deltaY) _pushItems(repeaterId, itemId, deltaY, true, true); 876 877 if(deltaX || deltaY) $ax.event.raiseSyntheticEvent(_createElementId(repeaterId, itemId), 'onItemResize'); 878 879 return true; 880 } 881 882 var _pushItems = _repeaterManager.pushItems = function (repeaterId, itemId, delta, vertical, suppressFire) { 883 if(delta == 0) return; 884 885 // Update repeater item size 886 var prop = vertical ? 'height' : 'width'; 887 var itemObj = $jobj(_createElementId(repeaterId, itemId)); 888 itemObj.css(prop, $ax.getNumFromPx(itemObj.css(prop)) + delta); 889 890 var repeaterObj = $jobj(repeaterId); 891 var repeaterMap = repeaterSizes[repeaterId]; 892 var sizes = repeaterMap.sizes; 893 var wrap = sizes[0].length != undefined; 894 var vert = repeaterMap.vert; 895 896 // Not wrapping, has to push in primary direction 897 if (!wrap && vert != vertical) { 898 var before = 0; 899 var after = 0; 900 var limit = 0; 901 for(var i = 0; i < sizes.length; i++) { 902 var size = sizes[i]; 903 if(size.itemId == itemId) { 904 before = size[prop]; 905 size[prop] += delta; 906 after = size[prop]; 907 } else { 908 limit = limit ? Math.max(limit, size[prop]) : size[prop]; 909 } 910 } 911 912 // Repeater delta is because an item can increase secondary direction, but if another item is already larger, then repeater size isn't effected. 913 var repeaterDelta = delta; 914 if(sizes.length != 1) { 915 if(after >= limit) repeaterDelta = after - Math.max(limit, before); 916 else if(before > limit) repeaterDelta = limit - before; 917 else repeaterDelta = 0; 918 } 919 920 _updateRepeaterSize(prop, repeaterObj, repeaterDelta); 921 922 if(!suppressFire) $ax.event.raiseSyntheticEvent(_createElementId(repeaterId, itemId), 'onItemResize'); 923 return; 924 } 925 926 var index = 0; 927 var index2 = 0; 928 // Get the indices first 929 if(wrap) { 930 outer: 931 for(; index < sizes.length; index++) { 932 var innerSizes = sizes[index]; 933 for(index2 = 0; index2 < innerSizes.length; index2++) if(innerSizes[index2].itemId == itemId) break outer; 934 } 935 } else { 936 for(; index < sizes.length; index++) if(sizes[index].itemId == itemId) break; 937 } 938 // Find out who is being pushed 939 var itemIdsEffected = []; 940 if (vert == vertical) { 941 // To check for repeater resize, non-wrap is easy, for wrap you have to see if your new size is enough to effect the size given other col/row sizes. 942 repeaterDelta = delta; 943 if(wrap && sizes.length > 1) { 944 var viewId = $ax.adaptive.currentViewId || ''; 945 var spacing = _getAdaptiveProp($obj(repeaterId).repeaterPropMap, (vert ? 'vertical' : 'horizontal') + 'Spacing', viewId); 946 for(i = 0; i < sizes.length; i++) { 947 var rowColSize = 0; 948 var rowCol = sizes[i]; 949 for(var j = 0; j < rowCol.length; j++) { 950 if(j != 0) rowColSize += spacing; 951 rowColSize += rowCol[j][prop]; 952 } 953 954 if(i == index) { 955 before = rowColSize; 956 after = before + delta; 957 } else { 958 limit = limit ? Math.max(limit, rowColSize) : rowColSize; 959 } 960 } 961 962 if(after >= limit) repeaterDelta = after - Math.max(limit, before); 963 else if (before > limit) repeaterDelta = limit - before; 964 else repeaterDelta = 0; 965 } 966 967 if (repeaterDelta) { 968 _updateRepeaterSize(prop, repeaterObj, repeaterDelta); 969 } 970 971 // Done the hard part, calculating/updating new repeater size. Now just resize items and find what to push. 972 var array = wrap ? sizes[index] : sizes; 973 i = wrap ? index2 : index; 974 array[i][prop] += delta; 975 976 for(i++; i < array.length; i++) itemIdsEffected.push(array[i].itemId); 977 } else { 978 // Secondary push is more interesting. See how much your primary row/column is already pushing, if that changes 979 // then effect all rows/columns after it 980 981 // Get the biggest one in the current row/column, ignoring the one we're changing 982 var biggest = 0; 983 var currSizes = sizes[index]; 984 for(i = 0; i < currSizes.length; i++) { 985 if (i == index2) continue; 986 987 biggest = Math.max(biggest, currSizes[i][prop]); 988 } 989 990 var beforeSize = Math.max(biggest, currSizes[index2][prop]); 991 currSizes[index2][prop] += delta; 992 var afterSize = Math.max(biggest, currSizes[index2][prop]); 993 994 // Nothing pushed/pulled 995 if (afterSize == beforeSize) return; 996 997 for(i = index + 1; i < sizes.length; i++) { 998 currSizes = sizes[i]; 999 for(j = 0; j < currSizes.length; j++) itemIdsEffected.push(currSizes[j].itemId); 1000 } 1001 1002 // Delta is only how much the whole row/column changed 1003 delta = afterSize - beforeSize; 1004 1005 // Repeater resize secondary is determined by the effective delta. 1006 _updateRepeaterSize(prop, repeaterObj, delta); 1007 } 1008 1009 for(i = 0; i < itemIdsEffected.length; i++) { 1010 var currItemId = itemIdsEffected[i]; 1011 var elementId = _createElementId(repeaterId, currItemId); 1012 var loc = vertical ? 'top' : 'left'; 1013 var jobj = $jobj(elementId); 1014 var currVal = Number(jobj.css(loc).replace('px', '')); 1015 jobj.css(loc, currVal + delta); 1016 } 1017 1018 if(!suppressFire) $ax.event.raiseSyntheticEvent(_createElementId(repeaterId, itemId), 'onItemResize'); 1019 } 1020 1021 var _updateRepeaterSize = function(prop, jobj, delta) { 1022 if (delta == 0) return; 1023 var val = $ax.getNumFromPx(jobj.css(prop)) + delta; 1024 var border = $ax.getNumFromPx(jobj.css('border-width')) || 0; 1025 val += border * 2; 1026 jobj.css(prop, val); 1027 $ax.dynamicPanelManager.fitParentPanel(jobj.attr('id')); 1028 } 1029 1030 var _getDataFromDataSet = function (eventInfo, repeaterId, itemId, propName, type) { 1031 var row = undefined; 1032 var deleteMap = eventInfo && eventInfo.repeaterDeleteMap && eventInfo.repeaterDeleteMap[repeaterId]; 1033 if(deleteMap) row = deleteMap.idToRow[itemId]; 1034 1035 if(!row) { 1036 var itemNum = _getRealItemId(eventInfo, repeaterId, Number(itemId)); 1037 row = repeaterToCurrentDataSet[repeaterId][itemNum]; 1038 } 1039 // Default to obj with text as empty string, as we don't generate the data for empty props 1040 var data = row[propName] || { text: '' }; 1041 //For now text is always the default. May change this to depend on context. 1042 return type == 'data' && data.type != 'text' ? data : (type && data[type]) || data['text']; 1043 }; 1044 _repeaterManager.getData = _getDataFromDataSet; 1045 1046 _repeaterManager.hasData = function(id, propName) { 1047 if(!_getItemIdFromElementId(id)) return false; 1048 var repeaterId = $ax.getParentRepeaterFromScriptId(_getScriptIdFromElementId(id)); 1049 return Boolean(repeaterToCurrentDataSet[repeaterId] && repeaterToCurrentDataSet[repeaterId].props.indexOf(propName) != -1); 1050 }; 1051 1052 var _getEventDeleteData = function(eventInfo, repeaterId) { 1053 var repeaterDeleteMap = eventInfo.repeaterDeleteMap; 1054 if(!repeaterDeleteMap) repeaterDeleteMap = eventInfo.repeaterDeleteMap = {}; 1055 1056 var myDeleteMap = repeaterDeleteMap[repeaterId]; 1057 if(!myDeleteMap) { 1058 myDeleteMap = repeaterDeleteMap[repeaterId] = {}; 1059 myDeleteMap.deletedIds = []; 1060 myDeleteMap.idToRow = {}; 1061 } 1062 1063 return myDeleteMap; 1064 }; 1065 1066 var _getRealItemId = function(eventInfo, repeaterId, itemId) { 1067 var deletedBefore = 0; 1068 var map = eventInfo.repeaterDeleteMap && eventInfo.repeaterDeleteMap[repeaterId]; 1069 var deletedIds = map && map.deletedIds; 1070 if(!deletedIds) return itemId - 1; 1071 1072 for(var i = 0; i < deletedIds.length; i++) if (deletedIds[i] < itemId) deletedBefore++; 1073 return itemId - deletedBefore - 1; 1074 } 1075 1076 var _addItemToDataSet = function(repeaterId, row, itemEventInfo) { 1077 itemEventInfo.data = true; 1078 var oldTarget = itemEventInfo.targetElement; 1079 itemEventInfo.targetElement = repeaterId; 1080 var dataSet = repeaterToLocalDataSet[repeaterId]; 1081 1082 for(var propName in row) { 1083 if(!row.hasOwnProperty(propName)) continue; 1084 var prop = row[propName]; 1085 if(prop.type == 'literal') { 1086 var retval = $ax.expr.evaluateExpr(prop.literal, itemEventInfo); 1087 if(typeof (retval) == 'string' || retval instanceof Date) retval = { type: 'text', text: retval }; 1088 row[propName] = retval; 1089 } 1090 } 1091 1092 itemEventInfo.targetElement = oldTarget; 1093 dataSet[dataSet.length] = row; 1094 itemEventInfo.data = false; 1095 }; 1096 _repeaterManager.addItem = _addItemToDataSet; 1097 1098 var _deleteItemsFromDataSet = function(repeaterId, eventInfo, type, rule) { 1099 var dataSet = repeaterToCurrentDataSet[repeaterId]; 1100 var deleteDataMap = _getEventDeleteData(eventInfo, repeaterId); 1101 var items; 1102 1103 // Should always be this, marked, or rule. 1104 if(type == 'this') items = [_getItemIdFromElementId(eventInfo.srcElement)]; 1105 else if(type == 'marked') items = $ax.deepCopy(repeaterToEditItems[repeaterId]); 1106 else { 1107 // This should be rule 1108 var visibleData = repeaterToCurrentDataSet[repeaterId]; 1109 items = []; 1110 var oldTarget = eventInfo.targetElement; 1111 for(var i = 0; i < visibleData.length; i++) { 1112 var index = i + 1; 1113 if(deleteDataMap.deletedIds.indexOf(index) != -1) continue; 1114 1115 eventInfo.targetElement = _createElementId(repeaterId, index); 1116 if($ax.expr.evaluateExpr(rule, eventInfo).toLowerCase() != 'true') continue; 1117 items.push(index); 1118 } 1119 eventInfo.targetElement = oldTarget; 1120 } 1121 // Want them decending 1122 items.sort(function(a, b) { return b - a; }); 1123 var editItems = repeaterToEditItems[repeaterId]; 1124 1125 for(i = 0; i < items.length; i++) { 1126 var itemId = items[i]; 1127 1128 // Don't delete already deletedItem 1129 if(deleteDataMap.deletedIds.indexOf(itemId) != -1) continue; 1130 1131 var deletedRow = $ax.splice(dataSet, _getRealItemId(eventInfo, repeaterId, itemId), 1)[0]; 1132 deleteDataMap.deletedIds.push(itemId); 1133 deleteDataMap.idToRow[itemId] = deletedRow; 1134 for(var j = editItems.length - 1; j >= 0; j--) { 1135 var editItem = editItems[j];
1136 if(editItem == itemId) $ax.splice(editItems, j, 1); 1137 else if(editItem > itemId) editItems[j] = editItem - 1; 1138 } 1139 } 1140 }; 1141 _repeaterManager.deleteItems = _deleteItemsFromDataSet; 1142 1143 var _updateEditItemsInDataSet = function(repeaterId, propMap, eventInfo, type, rule) { 1144 var oldTarget = eventInfo.targetElement; 1145 var dataSet = repeaterToCurrentDataSet[repeaterId]; 1146 var items; 1147 1148 // Should always be this, marked, or rule. 1149 if(type == 'this') items = [_getItemIdFromElementId(eventInfo.srcElement)]; 1150 else if(type == 'marked') items = repeaterToEditItems[repeaterId]; 1151 else { 1152 // This should be rule 1153 var currData = repeaterToCurrentDataSet[repeaterId]; 1154 items = []; 1155 oldTarget = eventInfo.targetElement; 1156 for(var i = 0; i < currData.length; i++) { 1157 var index = i + 1; 1158 eventInfo.targetElement = _createElementId(repeaterId, index); 1159 if($ax.expr.evaluateExpr(rule, eventInfo).toLowerCase() != 'true') continue; 1160 items.push(index); 1161 } 1162 eventInfo.targetElement = oldTarget; 1163 } 1164 1165 eventInfo.data = true; 1166 for(var prop in propMap) { 1167 if(!propMap.hasOwnProperty(prop)) continue; 1168 for(i = 0; i < items.length; i++) { 1169 var data = propMap[prop]; 1170 var item = items[i]; 1171 if(data.type == 'literal') { 1172 eventInfo.targetElement = _createElementId(repeaterId, item); 1173 data = $ax.expr.evaluateExpr(data.literal, eventInfo); 1174 if(typeof (data) == 'object' && data.isWidget) data = data.text; 1175 if(typeof (data) == 'string') data = { type: 'text', text: data }; 1176 } 1177 dataSet[_getRealItemId(eventInfo, repeaterId, item)][prop] = data; 1178 } 1179 } 1180 eventInfo.targetElement = oldTarget; 1181 eventInfo.data = false; 1182 }; 1183 _repeaterManager.updateEditItems = _updateEditItemsInDataSet; 1184 1185 var _getAllItemIds = function(repeaterId) { 1186 var retval = []; 1187 var currDataSet = repeaterToCurrentDataSet[repeaterId]; 1188 for(var i = 0; i < currDataSet.length; i++) retval.push(i + 1); 1189 return retval; 1190 }; 1191 _repeaterManager.getAllItemIds = _getAllItemIds; 1192 1193 var _addEditItemToRepeater = function(repeaterId, itemIds) { 1194 for(var i = 0; i < itemIds.length; i++) { 1195 var itemId = Number(itemIds[i]); 1196 var items = repeaterToEditItems[repeaterId]; 1197 if(items.indexOf(itemId) == -1) items[items.length] = itemId; 1198 } 1199 }; 1200 _repeaterManager.addEditItems = _addEditItemToRepeater; 1201 1202 var _removeEditItemFromRepeater = function(repeaterId, itemIds) { 1203 for(var i = 0; i < itemIds.length; i++) { 1204 var itemId = itemIds[i]; 1205 var items = repeaterToEditItems[repeaterId]; 1206 var index = items.indexOf(Number(itemId)); 1207 if(index != -1) $ax.splice(items, index, 1); 1208 } 1209 }; 1210 _repeaterManager.removeEditItems = _removeEditItemFromRepeater; 1211 1212 _repeaterManager.isEditItem = function(repeaterId, itemId) { 1213 var items = repeaterToEditItems[repeaterId]; 1214 return items.indexOf(Number(itemId)) != -1; 1215 }; 1216 1217 var _createElementId = function(scriptId, itemId) { 1218 if(!itemId) return scriptId; 1219 var i = scriptId.indexOf('_'); 1220 var sections = i > -1 ? [scriptId.substring(0, i), scriptId.substring(i + 1)] : [scriptId]; 1221 var retval = sections[0] + '-' + itemId; 1222 return sections.length > 1 ? retval + '_' + sections[1] : retval; 1223 }; 1224 _repeaterManager.createElementId = _createElementId; 1225 1226 var _getElementId = function(scriptId, childId) { 1227 var elementId = scriptId; 1228 if($ax.getParentRepeaterFromScriptId(scriptId)) { 1229 // Must be in the same item as the child 1230 var itemId = $ax.repeater.getItemIdFromElementId(childId); 1231 elementId = $ax.repeater.createElementId(scriptId, itemId); 1232 } 1233 return elementId; 1234 }; 1235 _repeaterManager.getElementId = _getElementId; 1236 1237 var _getScriptIdFromElementId = function(elementId) { 1238 if(!elementId) return elementId; 1239 var sections = elementId.split('-'); 1240 var retval = sections[0]; 1241 if(sections.length <= 1) return retval; 1242 sections = sections[1].split('_'); 1243 return sections.length > 1 ? retval + '_' + sections[1] : retval; 1244 }; 1245 _repeaterManager.getScriptIdFromElementId = _getScriptIdFromElementId; 1246 1247 var _getItemIdFromElementId = function(elementId) { 1248 var sections = elementId.split('-'); 1249 if(sections.length < 2) return ''; 1250 sections = sections[1].split('_'); 1251 return sections[0]; 1252 }; 1253 _repeaterManager.getItemIdFromElementId = _getItemIdFromElementId; 1254 1255 // TODO: Just inline this if we keep it this way. 1256 var _applySuffixToElementId = function(id, suffix) { 1257 return id + suffix; 1258 // return _createElementId(_getScriptIdFromElementId(id) + suffix, _getItemIdFromElementId(id)); 1259 }; 1260 _repeaterManager.applySuffixToElementId = _applySuffixToElementId; 1261 1262 var _removeSuffixFromElementId = function(id) { 1263 if (id.indexOf('_') != -1) return id.split('_', 1); 1264 return [id]; 1265 } 1266 _repeaterManager.removeSuffixFromElementId = _removeSuffixFromElementId; 1267 1268 // var _getRepeaterSize = function(repeaterId) { 1269 // var itemCount = ($ax.getItemIdsForRepeater(repeaterId) || []).length; 1270 // if(itemCount == 0) return { width: 0, height: 0 }; 1271 1272 // var repeater = $obj(repeaterId);
1273 // // Width and height per item; 1274 // var width = repeater.width; 1275 // var height = repeater.height; 1276 1277 // var viewId = $ax.adaptive.currentViewId || ''; 1278 // var widthIncrement = width + _getAdaptiveProp(repeater.repeaterPropMap, 'horizontalSpacing', viewId); 1279 // var heightIncrement = height + _getAdaptiveProp(repeater.repeaterPropMap, 'verticalSpacing', viewId); 1280 1281 // var wrap = _getAdaptiveProp(repeater.repeaterPropMap, 'wrap', viewId); 1282 // var vertical = _getAdaptiveProp(repeater.repeaterPropMap, 'vertical', viewId); 1283 1284 // if(wrap == -1 || itemCount <= wrap) { 1285 // if(vertical) height += heightIncrement * (itemCount - 1); 1286 // else width += widthIncrement * (itemCount - 1); 1287 // } else { 1288 // var primaryDim = wrap; 1289 // var secondaryDim = Math.ceil(itemCount / primaryDim); 1290 1291 // if(vertical) { 1292 // height += heightIncrement * (primaryDim - 1); 1293 // width += widthIncrement * (secondaryDim - 1); 1294 // } else { 1295 // width += widthIncrement * (primaryDim - 1); 1296 // height += heightIncrement * (secondaryDim - 1); 1297 // } 1298 // } 1299 // return { width: width, height: height }; 1300 // }; 1301 // _repeaterManager.getRepeaterSize = _getRepeaterSize; 1302 1303}); 1304 1305// ******* Dynamic Panel Manager ******** // 1306$axure.internal(function($ax) { 1307 // TODO: Probably a lot of the dynamic panel functions from pagescript should be moved here at some point... 1308 var _dynamicPanelManager = $ax.dynamicPanelManager = {}; 1309 1310 var _isIdFitToContent = _dynamicPanelManager.isIdFitToContent = function(id) { 1311 var obj = $obj(id); 1312 if (!obj || !$ax.public.fn.IsDynamicPanel(obj.type) || !obj.fitToContent) return false; 1313 1314 var jobj = $jobj($ax.visibility.GetPanelState(id)); 1315 return jobj.css('position') == 'relative'; 1316 }; 1317 1318 var _fitParentPanel = function(widgetId) { 1319 // Find parent panel if there is one. 1320 var parentPanelInfo = getParentPanel(widgetId); 1321 if(parentPanelInfo) { 1322 var parentId = parentPanelInfo.parent; 1323 if(_updateFitPanel(parentId, parentPanelInfo.state)) _fitParentPanel(parentId); 1324 return; 1325 } 1326 1327 // Otherwise, try to get parent repeater 1328 var parentRepeaterId = $ax.getParentRepeaterFromElementId(widgetId); 1329 var repeaterObj = $obj(parentRepeaterId); 1330 if(!repeaterObj || widgetId == parentRepeaterId || !repeaterObj.repeaterPropMap.fitToContent) return; 1331 var itemId = $ax.repeater.getItemIdFromElementId(widgetId); 1332 var size = getContainerSize($ax.repeater.createElementId(parentRepeaterId, itemId)); 1333 if($ax.repeater.setItemSize(parentRepeaterId, itemId, size.width, size.height)) _fitParentPanel(parentRepeaterId); 1334 }; 1335 _dynamicPanelManager.fitParentPanel = _fitParentPanel; 1336 1337 _dynamicPanelManager.initialize = function() { 1338 _dynamicPanelManager.initFitPanels($ax('*')); 1339 1340 $axure.resize(_handleResize); 1341 }; 1342 1343 _dynamicPanelManager.initFitPanels = function(query) { 1344 var fitToContent = []; 1345 query.each(function (obj, elementId) { 1346 var scriptId = $ax.repeater.getScriptIdFromElementId(elementId); 1347 if($ax.public.fn.IsDynamicPanel(obj.type) && obj.fitToContent && !$ax.visibility.isScriptIdLimbo(scriptId)) { 1348 fitToContent[fitToContent.length] = elementId; 1349 } 1350 }); 1351 for(var i = fitToContent.length - 1; i >= 0; i--) { 1352 var panelId = fitToContent[i]; 1353 var stateCount = $obj(panelId).diagrams.length; 1354 for(var j = 0; j < stateCount; j++) { 1355 // Traverse through children to find what size it should be. 1356 var stateId = $ax.repeater.applySuffixToElementId(panelId, '_state' + j); 1357 var stateContentId = stateId + '_content'; 1358 var stateQuery = $jobj(stateId); 1359 var size = getContainerSize(stateContentId); 1360 if(!$obj(panelId).percentWidth) stateQuery.width(size.
1360width); 1361 stateQuery.height(size.height); 1362 } 1363 } 1364 }; 1365 1366 var percentPanelToLeftCache = []; 1367 var percentPanelsInitialized = false; 1368 var _handleResize = function() { 1369 if(percentPanelsInitialized) { 1370 for(var key in percentPanelToLeftCache) { 1371 //could optimize to only update non-contained panels 1372 _updatePanelPercentWidth(key); 1373 } 1374 } else { 1375 $ax('*').each(function(obj, elementId) { 1376 if(_isPercentWidthPanel(obj)) _updatePanelPercentWidth(elementId); 1377 }); 1378 percentPanelsInitialized = true; 1379 } 1380 }; 1381 1382 var _isPercentWidthPanel = _dynamicPanelManager.isPercentWidthPanel = function(obj) { 1383 return obj && $ax.public.fn.IsDynamicPanel(obj.type) && obj.percentWidth; 1384 }; 1385 1386 _dynamicPanelManager.updatePanelContentPercentWidth = function(elementId) { 1387 // if(_isPercentWidthPanel($obj(elementId))) return; 1388 var stateChildrenQuery = $jobj(elementId).children('.panel_state'); 1389 stateChildrenQuery.children('.panel_state_content').each( 1390 function() { 1391 $(this).children('.ax_dynamic_panel').each( 1392 function() { _updatePanelPercentWidth(this.id); } 1393 ); 1394 } 1395 ); 1396 }; 1397 1398 _dynamicPanelManager.updatePercentPanelCache = function(query) { 1399 query.each(function(obj, elementId) { 1400 if(_isPercentWidthPanel(obj)) { 1401 if(_updatePercentPanelToLeftCache(obj, elementId, true)) { 1402 _updatePanelPercentWidth(elementId); 1403 } 1404 } 1405 }); 1406 }; 1407 1408 _dynamicPanelManager.resetFixedPanel = function(obj, domElement) { 1409 if(obj.fixedHorizontal == 'center') domElement.style.marginLeft = ""; 1410 if(obj.fixedVertical == 'middle') domElement.style.marginTop = ""; 1411 }; 1412 1413 _dynamicPanelManager.resetAdaptivePercentPanel = function(obj, domElement) { 1414 if(!_isPercentWidthPanel(obj)) return; 1415 1416 if(obj.fixedHorizontal == 'center') domElement.style.marginLeft = ""; 1417 else if(obj.fixedHorizontal == 'right') domElement.style.width = ""; 1418 }; 1419 1420 var _updatePercentPanelToLeftCache = function(obj, elementId, overwrite) { 1421 var wasUpdated = false; 1422 var jObj = $jobj(elementId); 1423 var axObj = $ax('#' + elementId); 1424 if(percentPanelToLeftCache[elementId] == undefined || overwrite) { 1425 if(obj.fixedHorizontal == 'center') percentPanelToLeftCache[elementId] = Number(jObj.css('margin-left').replace("px", "")); 1426 else if(obj.fixedHorizontal == 'right') percentPanelToLeftCache[elementId] = axObj.width() + Number(jObj.css('right').replace("px", "")); 1427 else percentPanelToLeftCache[elementId] = Number(jObj.css('left').replace("px", "")); 1428 wasUpdated = true; 1429 } 1430 1431 if(obj.fixedHorizontal == 'right' && _isIdFitToContent(elementId)) { 1432 var fitWidth = getContainerSize($ax.visibility.GetPanelState(elementId) + '_content').width; 1433 percentPanelToLeftCache[elementId] = fitWidth + Number(jObj.css('right').replace("px", "")); 1434 wasUpdated = true; 1435 } 1436 return wasUpdated; 1437 }; 1438 1439 var _updatePanelPercentWidth = _dynamicPanelManager.updatePanelPercentWidth = function(elementId) { 1440 var obj = $obj(elementId); 1441 if(!_isPercentWidthPanel(obj)) return; 1442 1443 _updatePercentPanelToLeftCache(obj, elementId, false); 1444 1445 var width; 1446 var x; 1447 1448 if(obj.fixedHorizontal) { 1449 x = 0; 1450 width = $(window).width(); 1451 } else { 1452 var parentPanelInfo = getParentPanel(elementId); 1453 if(parentPanelInfo) { 1454 var parentId = parentPanelInfo.parent; 1455 width = $ax('#' + parentId).width(); 1456 var parentObj = $obj(parentId); 1457 if(parentObj.percentWidth) { 1458 var stateId = $ax.repeater.applySuffixToElementId(parentId, '_state' + parentPanelInfo.state); 1459 var stateContentId = stateId + '_content'; 1460 x = -Number($jobj(stateContentId).css('margin-left').replace("px", "")); 1461 } else x = 0; 1462 } else { 1463 var parentRepeater = $ax.getParentRepeaterFromScriptId($ax.repeater.getScriptIdFromElementId(elementId)); 1464 if(parentRepeater) { 1465 var itemId = $ax.repeater.getItemIdFromElementId(elementId); 1466 var itemContainerId = $ax.repeater.createElementId(parentRepeater, itemId); 1467 x = 0; 1468 width = $ax('#' + itemContainerId).width(); 1469 } else { 1470 var $window = $(window); 1471 width = $window.width(); 1472 var bodyLeft = Number($('body').css('left').replace("px", "")); 1473 var bodyWidth = Number($('body').css('width').replace("px", "")); 1474 var isCenter = $ax.adaptive.getPageStyle().pageAlignment == 'center'; 1475 width = Math.max(width, bodyWidth); 1476 x = isCenter ? -(width - bodyWidth) / 2 - bodyLeft : 0; 1477 } 1478 } 1479 } 1480 1481 var jObj = $jobj(elementId); 1482 if(obj.fixedHorizontal == 'left') jObj.css('left', x + 'px'); 1483 else if(obj.fixedHorizontal == 'center') { 1484 jObj.css('left', x + 'px'); 1485 jObj.css('margin-left', 0 + 'px'); 1486 } else jObj.css('left', x + 'px'); 1487 1488 jObj.css('width', width + 'px'); 1489 1490 var panelLeft = percentPanelToLeftCache[elementId]; 1491 var stateChildrenQuery = jObj.children('.panel_state'); 1492 stateChildrenQuery.css('width', width + 'px'); 1493 1494 if(obj.fixedHorizontal == 'center') 1495 stateChildrenQuery.children('.panel_state_content').css('left', '50%').css('margin-left', panelLeft + 'px'); 1496 else if(obj.fixedHorizontal == 'right') 1497 stateChildrenQuery.children('.panel_state_content').css('left', width - panelLeft + 'px'); 1498 else stateChildrenQuery.children('.panel_state_content').css('margin-left', panelLeft - x + 'px'); 1499 }; 1500 1501 _dynamicPanelManager.updateAllFitPanels = function() { 1502 var fitToContent = []; 1503 $ax('*').each(function (obj, elementId) { 1504 var scriptId = $ax.repeater.getScriptIdFromElementId(elementId); 1505 if($ax.public.fn.IsDynamicPanel(obj.type) && obj.fitToContent && !$ax.visibility.isScriptIdLimbo(scriptId)) { 1506 fitToContent[fitToContent.length] = elementId; 1507 } 1508 }); 1509 for(var i = fitToContent.length - 1; i >= 0; i--) { 1510 var panelId = fitToContent[i]; 1511 var stateCount = $obj(panelId).diagrams.length; 1512 for(var j = 0; j < stateCount; j++) { 1513 $ax.dynamicPanelManager.setFitToContentCss(panelId, true); 1514 _updateFitPanel(panelId, j, true); 1515 } 1516 } 1517 }; 1518 1519 _dynamicPanelManager.setFitToContentCss = function(elementId, fitToContent, oldWidth, oldHeight) { 1520 1521 if($ax.dynamicPanelManager.isIdFitToContent(elementId) == fitToContent) return; 1522 1523 var panel = $jobj(elementId); 1524 var stateCss; 1525 var scrollbars = $obj(elementId).scrollbars; 1526 1527 if(fitToContent) { 1528 panel.attr('style', ''); 1529 stateCss = {}; 1530 stateCss.position = 'relative'; 1531 if(scrollbars != 'none') { 1532 stateCss.overflow = 'visible'; 1533 stateCss['-webkit-overflow-scrolling'] = 'visible'; 1534 } 1535 if(scrollbars == 'verticalAsNeeded') { 1536 stateCss['overflow-x'] = 'visible'; 1537 stateCss['-ms-overflow-x'] = 'visible'; 1538 } else if(scrollbars == 'horizontalAsNeeded') { 1539 stateCss['overflow-y'] = 'visible'; 1540 stateCss['-ms-overflow-y'] = 'visible'; 1541 } 1542 panel.children().css(stateCss); 1543 } else { 1544 var panelCss = { width: oldWidth, height: oldHeight }; 1545 stateCss = { width: oldWidth, height: oldHeight }; 1546 panelCss.overflow = 'hidden'; 1547 stateCss.position = 'absolute'; 1548 if(scrollbars != 'none') { 1549 stateCss.overflow = 'auto'; 1550 stateCss['-webkit-overflow-scrolling'] = 'touch'; 1551 } 1552 if(scrollbars == 'verticalAsNeeded') { 1553 stateCss['overflow-x'] = 'hidden'; 1554 stateCss['-ms-overflow-x'] = 'hidden'; 1555 } else if(scrollbars == 'horizontalAsNeeded') { 1556 stateCss['overflow-y'] = 'hidden'; 1557 stateCss['-ms-overflow-y'] = 'hidden'; 1558 } 1559 panel.css(panelCss); 1560 panel.children().css(stateCss); 1561 } 1562 }; 1563 1564 var _getShownStateId = function (id) { 1565 var obj = $obj(id); 1566 if (!obj || !$ax.public.fn.IsDynamicPanel(obj.type)) return id; 1567 1568 var children = $ax.visibility.applyWidgetContainer(id, true).children();
1569 for (var i = 0; i < children.length; i++) { 1570 var child = children[i]; 1571 while ($ax.visibility.isContainer(child.id)) child = $(child).children()[0]; 1572 if (child && child.style && child.style.display != 'none') return child.id; 1573 } 1574 return id; 1575 }; 1576 1577 var _getShownStateObj = function(id) { return $ax('#' + _getShownStateId(id));} 1578 1579 _dynamicPanelManager.getShownState = function (id) { return $jobj(_getShownStateId(id)); }; 1580 1581 var _getClamp = function(id) { 1582 var obj = $obj(id); 1583 if(!obj) return $ax('#' + id); 1584 if ($ax.public.fn.IsDynamicPanel(obj.type)) return _getShownStateObj(id); 1585 return $ax('#' + id); 1586 }; 1587 1588 var _updateFitPanel = function(panelId, stateIndex, initializingView) { 1589 if(!panelId) return false; 1590 1591 // Only fit if fitToContent is true 1592 if(!$ax.dynamicPanelManager.isIdFitToContent(panelId)) return false; 1593 1594 // Traverse through children to find what size it should be. 1595 var stateId = $ax.repeater.applySuffixToElementId(panelId, '_state' + stateIndex); 1596 var stateContentId = stateId + '_content'; 1597 var stateQuery = $jobj(stateId); 1598 var size = getContainerSize(stateContentId); 1599 1600 // Skip if size hasn't changed 1601 var oldWidth = stateQuery.width(); 1602 var oldHeight = stateQuery.height(); 1603 if(oldWidth == size.width && oldHeight == size.height) return false; 1604 1605 if(!$obj(panelId).percentWidth) stateQuery.width(size.width); 1606 stateQuery.height(size.height); 1607 1608 //updatePercentWidth on all child panels 1609 $jobj(stateContentId).children('.ax_dynamic_panel').each( 1610 function() { _updatePanelPercentWidth(this.id); } 1611 ); 1612 1613 //do the following only if it is the current state 1614 if(stateId != $ax.visibility.GetPanelState(panelId)) return false; 1615 1616 if(!initializingView) _adjustFixed(panelId, oldWidth, oldHeight, size.width, size.height); 1617 else if(stateIndex != 0) { 1618 var state0 = $jobj($ax.repeater.applySuffixToElementId(panelId, '_state0')); 1619 _adjustFixed(panelId, state0.width(), state0.height(), size.width, size.height); 1620 } 1621 1622 $ax.event.raiseSyntheticEvent(panelId, 'onResize'); 1623 $ax.flyoutManager.updateFlyout(panelId); 1624 1625 return true; 1626 }; 1627 1628 // widgetId is the one that crawls up masters until it finds a parent panel, targetId is the original widgetId (not the crawling master) 1629 var getParentPanel = function(widgetId, path, targetId) { 1630 path = path || $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(widgetId)); 1631 1632 var obj = $obj(widgetId); 1633 if(obj.parentDynamicPanel) { 1634 path[path.length - 1] = obj.parentDynamicPanel; 1635 var parentId = $ax.getScriptIdFromPath(path); 1636 if(!parentId) return undefined; 1637 parentId = $ax.repeater.getElementId(parentId, widgetId); 1638 var parentObj = $obj(parentId); 1639 var retVal = { parent: parentId }; 1640 for(var i = 0; i < parentObj.diagrams.length; i++) { 1641 var stateId = $ax.repeater.applySuffixToElementId(parentId, '_state' + i); 1642 var stateQuery = $jobj(stateId); 1643 if(stateQuery.find('#' + (targetId || widgetId)).length != 0) { 1644 retVal.state = i; 1645 break; 1646 } 1647 } 1648 return retVal; 1649 } 1650 1651 if(path.length == 1) return undefined; 1652 1653 path.pop(); 1654 var parentMaster = $ax.getScriptIdFromPath(path); 1655 if(!parentMaster) return undefined; 1656 parentMaster = $ax.repeater.getElementId(parentMaster, widgetId); 1657 1658 return getParentPanel(parentMaster, path, targetId || widgetId); 1659 }; 1660 1661 // TODO: May be a better location for this. Used currently for rdo and panel state containers 1662 var getContainerSize = function(containerId) { 1663 var containerQuery = containerId ? $jobj(containerId) : $('#base'); 1664 var children = containerQuery.children();
1665 // Default size 1666 var size = { width: 0, height: 0 }; 1667 for(var i = 0; i < children.length; i++) { 1668 var child = $(children[i]); 1669 var childId = child.attr('id'); 1670 //var axChild = $ax('#' + childId).width(); 1671 1672 var childObj = $obj(childId); 1673 if(!childObj) { 1674 // On the body there are some children that should be ignored, as they are not objects. 1675 if(!child.hasClass('basiclink') || child.get(0).tagName.toLowerCase() != 'a') continue; 1676 1677 // Otherwise it should be a basic link 1678 var linkChildren = child.children(); 1679 if(!linkChildren.length) continue; 1680 child = $(linkChildren[0]); 1681 childId = child.attr('id'); 1682 childObj = $obj(childId); 1683 } 1684 1685 // Ignore fixed 1686 if(!childId || $ax.visibility.limboIds[childId] || !$ax.visibility.IsIdVisible(childId) 1687 || $ax.public.fn.IsDynamicPanel(childObj.type) && childObj.fixedHorizontal) continue; 1688 1689 var boundingRect = $ax.public.fn.getWidgetBoundingRect(childId); 1690 var position = { left: boundingRect.left, top: boundingRect.top }; 1691 var width = boundingRect.width; 1692 var height = boundingRect.height; 1693 1694 if($ax.public.fn.IsMaster(childObj.type)) { 1695 var masterSize = getContainerSize(childId); 1696 width = masterSize.width; 1697 height = masterSize.height; 1698 // } else if($ax.public.fn.IsRepeater(childObj.type)) { 1699 // var repeaterSize = $ax.repeater.getRepeaterSize(childId); 1700 // width = repeaterSize.width; 1701 // height = repeaterSize.height; 1702 1703 // if(width == 0 && height == 0) continue; 1704 1705 // position.left += childObj.x; 1706 // position.top += childObj.y; 1707 } else if ($ax.public.fn.IsDynamicPanel(childObj.type)) { 1708 if($ax.dynamicPanelManager.isIdFitToContent(childId)) { 1709 var stateQuery = $jobj($ax.visibility.GetPanelState(childId)); 1710 width = stateQuery.width(); 1711 height = stateQuery.height(); 1712 } 1713 } 1714 1715 size.width = Math.max(size.width, position.left + width); 1716 size.height = Math.max(size.height, position.top + height); 1717 } 1718 1719 return size; 1720 }; 1721 1722 var _adjustFixed = _dynamicPanelManager.adjustFixed = function(panelId, oldWidth, oldHeight, width, height) { 1723 var loc = _getFixedPosition(panelId, oldWidth, oldHeight, width, height); 1724 if(loc) { 1725 $ax.action.addAnimation(panelId, $ax.action.queueTypes.move, function() { 1726 $ax.move.MoveWidget(panelId, loc[0], loc[1], { easing: 'none', duration: 0 }, false, null, true); 1727 }); 1728 } 1729 }; 1730 1731 var _getFixedPosition = _dynamicPanelManager.getFixedPosition = function(panelId, oldWidth, oldHeight, width, height) { 1732 var panelObj = $obj(panelId); 1733 var x = 0; 1734 var y = 0; 1735 if(panelObj.fixedHorizontal == 'center') { 1736 x = (oldWidth - width) / 2; 1737 } 1738 if(panelObj.fixedVertical == 'middle') { 1739 y = (oldHeight - height) / 2; 1740 } 1741 return x == 0 && y == 0 ? undefined : [x, y]; 1742 }; 1743 1744 _dynamicPanelManager.getFixedInfo = function(panelId) { 1745 var panelObj = $obj(panelId); 1746 if (!panelObj || !$ax.public.fn.IsDynamicPanel(panelObj.type)) return {}; 1747 var jobj = $jobj(panelId); 1748 if(jobj.css('position') == 'absolute') return {}; 1749 1750 var info = {}; 1751 var horizontal = panelObj.fixedHorizontal; 1752 if(!horizontal) return info; 1753 1754 info.fixed = true; 1755 info.horizontal = horizontal; 1756 info.vertical = panelObj.fixedVertical; 1757 1758 if(info.horizontal == 'left') info.x = Number(jobj.css('left').replace('px', '')); 1759 else if(info.horizontal == 'center') info.x = Number(jobj.css('margin-left').replace('px', '')); 1760 else if(info.horizontal == 'right') info.x = Number(jobj.css('right').replace('px', '')); 1761
1762 if(info.vertical == 'top') info.y = Number(jobj.css('top').replace('px', '')); 1763 else if(info.vertical == 'middle') info.y = Number(jobj.css('margin-top').replace('px', '')); 1764 else if(info.vertical == 'bottom') info.y = Number(jobj.css('bottom').replace('px', '')); 1765 1766 return info; 1767 }; 1768 1769 // Show isn't necessary if this is always done before toggling (which is currently true), but I don't want that 1770 // change (if it happened) to break this. 1771 var _compressToggle = function (id, vert, show, easing, duration) { 1772 var layer = $ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE; 1773 var locProp = vert ? 'top' : 'left'; 1774 var dimProp = vert ? 'height' : 'width'; 1775 1776 var threshold; 1777 var delta; 1778 1779 threshold = $ax('#' + id)[locProp](true); 1780 delta = layer ? $ax('#' + id)[dimProp]() : _getShownStateObj(id)[dimProp](); 1781 1782 if(!show) { 1783 // Need to make threshold bottom/right 1784 threshold += delta; 1785 // Delta is in the opposite direction 1786 delta *= -1; 1787 } 1788 1789 _compress(id, vert, threshold, delta, easing, duration); 1790 }; 1791 _dynamicPanelManager.compressToggle = _compressToggle; 1792 1793 // Used when setting state of dynamic panel 1794 var _compressDelta = function(id, oldState, newState, vert, easing, duration) { 1795 var oldQuery = $jobj(oldState); 1796 var newQuery = $jobj(newState); 1797 1798 var thresholdProp = vert ? 'top' : 'left'; 1799 var thresholdOffset = vert ? 'height' : 'width'; 1800 var threshold = $ax('#' + id)[thresholdProp](true); 1801 threshold += oldQuery[thresholdOffset](); 1802 1803 var delta = newQuery[thresholdOffset]() - oldQuery[thresholdOffset](); 1804 1805 var clampOffset = vert ? 'width' : 'height'; 1806 var clampWidth = Math.max(oldQuery[clampOffset](), newQuery[clampOffset]()); 1807 1808 _compress(id, vert, threshold, delta, easing, duration, clampWidth); 1809 }; 1810 _dynamicPanelManager.compressDelta = _compressDelta; 1811 1812 var _compress = function (id, vert, threshold, delta, easing, duration, clampWidth) { 1813 // If below, a horizantal clamp, otherwise a vertical clamp 1814 var clamp = { 1815 prop: vert ? 'left' : 'top', 1816 offset: vert ? 'width' : 'height' 1817 }; 1818 1819 // Get clamp in coords relative to parent. Account for layers farther down 1820 if($ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE) { 1821 clamp.start = $ax('#' + id)[clamp.prop](true); 1822 clamp.end = clamp.start + $ax('#' + id)[clamp.offset](); 1823 } else { 1824 var clampLoc = $jobj(id); 1825 if(typeof clampWidth == 'undefined') clampWidth = _getClamp(id)[clamp.offset](); 1826 1827 clamp.start = Number(clampLoc.css(clamp.prop).replace('px', '')); 1828 1829 clamp.end = clamp.start + clampWidth; 1830 } 1831
1832 // If clamps, threshold, or delta is not a number, can't compress. 1833 if (isNaN(clamp.start) || isNaN(clamp.end) || isNaN(threshold) || isNaN(delta)) return; 1834 1835 // Update clamp if fixed, to account for body position (only necessary when page centered) 1836 if($jobj(id).css('position') == 'fixed') { 1837 var clampDelta = $('#base').position().left; 1838 clamp.start -= clampDelta; 1839 clamp.end -= clampDelta; 1840 } 1841 1842 if(!easing) { 1843 easing = 'none'; 1844 duration = 0; 1845 } 1846 var parent = $ax('#' + id).getParents(false, ['item', 'state', 'layer'])[0]; 1847 var obj = parent && $ax.getObjectFromElementId($ax.repeater.removeSuffixFromElementId(parent)[0]); 1848 // Go until you hit a parent item or state, or a layer that is hidden to use as parent. 1849 // Account for layer container positions as you go. 1850 while(obj && $ax.public.fn.IsLayer(obj.type) && $ax.visibility.IsIdVisible(parent)) { 1851 var container = $ax.visibility.applyWidgetContainer(parent, true, true); 1852 // If layer is using container, offset is going to be necessary 1853 if(container.length) { 1854 var offsetX = $ax.getNumFromPx(container.css('left')); 1855 var offsetY = $ax.getNumFromPx(container.css('top')); 1856 var clampProp = clamp.prop == 'left' ? offsetX : offsetY; 1857 var threshProp = clamp.prop == 'left' ? offsetY : offsetX; 1858 threshold += threshProp; 1859 clamp.start += clampProp; 1860 clamp.end += clampProp; 1861 } 1862 1863 parent = $ax('#' + parent).getParents(false, ['item', 'state', 'layer'])[0]; 1864 obj = parent && $ax.getObjectFromElementId($ax.repeater.removeSuffixFromElementId(parent)[0]); 1865 } 1866 1867 // Add container mid push causes strange behavior because we take container into account as we go down, but if after we accounted for it, 1868 // a container is added, that container is not accounted for with threshold and clamp values. 1869 var layer = obj && $ax.public.fn.IsLayer(obj.type) && parent; 1870 if(layer) { 1871 // If your parent layer is invisible, you want to be relative to it's container. That is true already if it has a container, 1872 // but if you are just adding one now, then you need to offset your values 1873 var needsOffset = !$jobj(layer + '_container').length && !$ax.visibility.IsIdVisible(layer); 1874 $ax.visibility.pushContainer(layer, false); 1875 if(needsOffset) { 1876 container = $jobj(layer + '_container'); 1877 offsetX = $ax.getNumFromPx(container.css('left')); 1878 offsetY = $ax.getNumFromPx(container.css('top')); 1879 clampProp = clamp.prop == 'left' ? offsetX : offsetY; 1880 threshProp = clamp.prop == 'left' ? offsetY : offsetX; 1881 threshold -= threshProp; 1882 clamp.start -= clampProp; 1883 clamp.end -= clampProp; 1884 } 1885 } 1886 1887 // Note: If parent is body, some of these aren't widgets 1888 if(parent && $jobj(parent + '_content').length > 0) parent = parent + '_content'; 1889 if(parent && $jobj(parent + '_container').length > 0) parent = parent + '_container'; 1890 _compressChildrenHelper(id, $(parent ? '#' + parent : '#base').children(), vert, threshold, delta, clamp, easing, duration); 1891 1892 if(layer) $ax.visibility.popContainer(layer, false); 1893 1894 // Do item push 1895 var itemId = $ax.repeater.getItemIdFromElementId(id); 1896 if(!itemId) return; 1897 1898 var repeaterId = $ax.getParentRepeaterFromElementId(id); 1899 // Only need to push when parent is an item directly. 1900 if(parent != $ax.repeater.createElementId(repeaterId, itemId)) return; 1901 1902 // If repeater is fit to content, then don't worry about it, it'll be handled elsewhere 1903 if(!obj.repeaterPropMap.fitToContent) $ax.repeater.pushItems(repeaterId, itemId, delta, vert); 1904 }; 1905 1906 var _compressChildrenHelper = function (id, children, vert, threshold, delta, clamp, easing, duration, parentLayer) { 1907 var toMove = []; 1908 var allMove = true; 1909 for (var i = 0; i < children.length; i++) { 1910 var child = $(children[i]); 1911 1912 //don't move fixed 1913 if(child.css('position') == 'fixed') continue; 1914 1915 // Check for basic links 1916 if(child[0] && child[0].tagName == 'A' && child.hasClass('basiclink')) child = child.children();
1917 var childId = child.attr('id'); 1918 1919 // Don't move self, and check id to make sure it is a widget. 1920 if(childId == id || !childId || childId[0] != 'u') { 1921 allMove = false; 1922 continue; 1923 } 1924 1925 if ($ax.getTypeFromElementId(childId) == $ax.constants.LAYER_TYPE) { 1926 $ax.visibility.pushContainer(childId, false); 1927 var addSelf; 1928 var container = $ax.visibility.applyWidgetContainer(childId, true, true); 1929 var layerChildren = $ax.visibility.getRealChildren(child.children()); 1930 //if(container.length) { 1931 var offsetX = -$ax.getNumFromPx(container.css('left')); 1932 var offsetY = -$ax.getNumFromPx(container.css('top')); 1933 var clampProp = clamp.prop == 'left' ? offsetX : offsetY; 1934 var threshProp = clamp.prop == 'left' ? offsetY : offsetX; 1935 var layerClamp = { prop: clamp.prop, offset: clamp.offset, start: clamp.start + clampProp, end: clamp.end + clampProp }; 1936 addSelf = _compressChildrenHelper(id, layerChildren, vert, threshold + threshProp, delta, layerClamp, easing, duration, childId); 1937 //} else addSelf = _compressChildrenHelper(id, layerChildren, vert, threshold, delta, clamp, easing, duration, childId); 1938 1939 if(addSelf) toMove.push(childId); 1940 else allMove = false; 1941 $ax.visibility.popContainer(childId, false); 1942 continue; 1943 } 1944 1945 var numbers = childId.substring(1).split('-'); 1946 if(numbers.length < 1 || isNaN(Number(numbers[0])) || (numbers.length == 2 && isNaN(Number(numbers[1]))) || numbers.length > 2) continue; 1947 1948 var marker, childClamp; 1949 1950 var axChild = $ax('#' + childId); 1951 var markerProp = vert ? 'top' : 'left'; 1952 marker = Number(axChild[markerProp](true)); 1953 childClamp = [Number(axChild[clamp.prop](true))]; 1954 // Dynamic panels are not reporting correct size sometimes, so pull it from the state. Get shown state just returns the widget if it is not a dynamic panel. 1955 var sizeChild = _getShownStateObj(childId); 1956 childClamp[1] = childClamp[0] + sizeChild[clamp.offset](); 1957 1958 if(isNaN(marker) || isNaN(childClamp[0]) || isNaN(childClamp[1]) || 1959 marker < threshold || childClamp[1] <= clamp.start || childClamp[0] >= clamp.end) { 1960 allMove = false; 1961 continue; 1962 } 1963 1964 if (allMove && parentLayer) { 1965 //should i nopmove here? 1966 //$ax.move.nopMove(childId); 1967 $ax.event.raiseSyntheticEvent(childId, "onMove"); 1968 } 1969 toMove.push(childId); 1970 } 1971 1972 if (allMove && parentLayer) { 1973 return true; 1974 } else { 1975 for(var i = 0; i < toMove.length; i++) { 1976 $ax('#' + toMove[i]).moveBy(vert ? 0 : delta, vert ? delta : 0, easing == 'none' ? {} : { duration: duration, easing: easing }); 1977 } 1978 } 1979 return false; 1980 }; 1981 1982 var _parentHandlesStyles = function(id) { 1983 var parents = $ax('#' + id).getParents(true, ['dynamicPanel', 'layer'])[0]; 1984 if(!parents) return false; 1985 var directParent = true; 1986 for(var i = 0; i < parents.length; i++) { 1987 var parentId = parents[i]; 1988 var parentObj = $obj(parentId); 1989 if(!parentObj.propagate) { 1990 directParent = false; 1991 continue; 1992 } 1993 return { id: parentId, direct: directParent }; 1994 } 1995 return false; 1996 }; 1997 _dynamicPanelManager.parentHandlesStyles = _parentHandlesStyles; 1998 1999 var _propagateMouseOver = function(id, value) { 2000 propagate(id, true, value); 2001 }; 2002 _dynamicPanelManager.propagateMouseOver = _propagateMouseOver; 2003 2004 var _propagateMouseDown = function(id, value) { 2005 propagate(id, false, value); 2006 }; 2007 _dynamicPanelManager.propagateMouseDown = _propagateMouseDown; 2008 2009 var propagate = function(id, hover, value) { 2010 var hoverChildren = function(children) { 2011 if(!children) return; 2012 for(var i = 0; i < children.length; i++) { 2013 var elementId = children[i].id; 2014 var obj = $obj(elementId); 2015 if(obj == null) { 2016 elementId = elementId.split('_')[0]; 2017 obj = $obj(elementId); 2018 } 2019 if(obj == null) continue; 2020 if (($ax.public.fn.IsDynamicPanel(obj.type) || $ax.public.fn.IsLayer(obj.type)) && !obj.propagate) continue; 2021 2022 if(hover) $ax.style.SetWidgetHover(elementId, value); 2023 else $ax.style.SetWidgetMouseDown(elementId, value); 2024 $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId)); 2025 2026 hoverChildren(children[i].children); 2027 } 2028 }; 2029 hoverChildren($ax('#' + id).getChildren(true)[0].children); 2030 }; 2031});
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.