PageSourceSearch

https://www.wepe.cn/resources/scripts/axure/repeater.js

js wepe.cn collected 2026-10-04 01:42:10 UTC 90,686 bytes, 2,031 lines download raw bytes

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.