<commit_before>
angular.module('NSysMonApp').controller('CtrlMemGc', function($scope, $log, Rest) {
    $('.btn').tooltip({
        container: 'body',
        html: true
    });

    //TODO display committed and maximum memory
    //TODO get 'current' memory consumption in addition to GC requests
    //TODO tool tip: left or right, depending on x coordinate

    $scope.safeApply = function(fn) {
        var phase = this.$root.$$phase;
        if(phase == '$apply' || phase == '$digest') {
            if(fn && (typeof(fn) === 'function')) {
                fn();
            }
        } else {
            this.$apply(fn);
        }
    };

    $scope.showFullGcMarkers = true;
    $scope.$watch('showFullGcMarkers', function() {
        if($scope.gcs) {
            $scope.dataAsMap['_full_'].points.show = $scope.showFullGcMarkers;
            extractGcMarkings($scope.gcs);
            doPlot();
        }
    });

    $scope.showOtherGcMarkers = false;
    $scope.$watch('showOtherGcMarkers', function() {
        if($scope.gcs) {
            extractGcMarkings($scope.gcs);
            doPlot();
        }
    });

    $scope.showLegend = true;
    $scope.$watch('showLegend', function() {
        if($scope.gcs) {
            doPlot();
        }
    });

    function endMillis(gc) {
        return gc.durationNanos < 1000*1000 ? gc.startMillis : (gc.startMillis + gc.durationNanos / 1000 / 1000);
    }

    function isFullGc(gc) {
        return gc.type.indexOf(' major ') !== -1;
    }

    function extractGcMarkings(gcs) {
        $scope.gcMarkings = [];

        for(var i=0; i<gcs.length; i++) {
            var gc = gcs[i];
            if(isFullGc(gc) && $scope.showFullGcMarkers) {
                $scope.gcMarkings.push({color: 'rgba(0,0,100,.8)', lineWidth: 1, xaxis: {from: gc.startMillis, to: endMillis(gc)}});
            }
            if(! isFullGc(gc) && $scope.showOtherGcMarkers) {
                $scope.gcMarkings.push({color: 'rgba(50,50,150,.7)', lineWidth: 1, xaxis: {from: gc.startMillis, to: endMillis(gc)}});
            }
        }
    }

    function initFromResponse(data) {
        $scope.gcs = data.gcs;

        $scope.startTime = undefined;
        if(data.gcs && data.gcs.length) {
            $scope.startTime = new Date(data.gcs[0].startMillis);
        }
        $scope.endTime = new Date();
        $scope.dataSets = [];
        $scope.gcMarkings = [];

        function extractDataAsMap () {
            var result = {};

            if(data.gcs && data.gcs.length) {
                $scope.xMinData = data.gcs[0].startMillis;
            }
            for(var i=0; i<data.gcs.length; i++) {
                var gc = data.gcs[i];

                for(var memKind in gc.mem) {
                    if(!gc.mem.hasOwnProperty(memKind)) continue;
                    if(! result[memKind]) {
                        result[memKind] = {
                            label: memKind,
                            hoverable: false,
                            data: []
                        };
                    }

                    var end = endMillis(gc);
                    $scope.xMaxData = end;
                    result[memKind].data.push([gc.startMillis, gc.mem[memKind].usedBefore / 1024 / 1024]);
                    result[memKind].data.push([end, gc.mem[memKind].usedAfter / 1024 / 1024]);
                }
                if(!result['_full_']) {
                    result['_full_'] = {
                        label: '_full_',
                        data: [],
                        lines: {show: false},
                        color: 'rgb(0,0,100)',
                        points: {show: true, radius: 7, fill: true, fillColor: 'rgb(100, 100, 200)'}
                    }
                }
                if(isFullGc(gc)) {
                    result['_full_'].data.push([gc.startMillis, 0]);
                }
            }
            $scope.xMinDisplay = $scope.xMinData;
            $scope.xMaxDisplay = $scope.xMaxData;

            return result;
        }

        function sortedMemKinds(dataAsMap) {
            var result = [];
            for(var memKind in dataAsMap) {
                if(!dataAsMap.hasOwnProperty(memKind)) continue;
                result.push(memKind);
            }
            result.sort(function(a,b) {
                var aOrder = memKindSortOrder[a];
                var bOrder = memKindSortOrder[b];

                if(aOrder && bOrder) return aOrder - bOrder;
                if(!aOrder) return 1;
                if(!bOrder) return -1;
                return a < b ? -1 : 1;
            });

            return result;
        }

        if(data.gcs && data.gcs.length) {
            $scope.dataAsMap = extractDataAsMap();
            var memKinds = sortedMemKinds($scope.dataAsMap);

            $scope.dataSets = [];
            for(var i=0; i<memKinds.length; i++) {
                $scope.dataSets.push($scope.dataAsMap[memKinds[i]]);
            }

            extractGcMarkings(data.gcs);
        }
    }

    var memKindSortOrder = {
        'PS Perm Gen': 1,
        'PS Old Gen': 2,
        'PS Survivor Space': 3,
        'PS Eden Space': 4,
        '_full_': 10
    };

    function sendCommand(cmd) {
        Rest.call(cmd, function(data) {
            initFromResponse(data);
            doPlot();
        });
    }

    $scope.refresh = function() {
        sendCommand('getData');
    };

    $scope.refresh();

    var plot;
    function doPlot() {
        plot = $.plot(
            '#mem-gc-placeholder',
            $scope.dataSets,
            {
                legend: {
                    show: $scope.showLegend,
                    position: 'ne',
                    backgroundOpacity: .7,
                    labelFormatter: function(label) {return label.charAt(0) === '_' ? null : label;}
                },
                xaxis: {
                    mode: 'time',
                    timezone: 'browser'
                },
                yaxis: {
                    axisLabel: 'Memory Size (MB)',
                    zoomRange: false, // flot.navigate
                    panRange: false, // flot.navigate
                    transform: function(v) {return v;}
                },
                series: {stack: true},
//                colors: [0, 1, 2, 3, 4, 5, 6],
                lines: {
                    lineWidth: 1,
                    fill: true
                },
                grid: {
                    hoverable: true,
                    mouseActiveRadius: 15,
//                    backgroundColor: { colors: ["#D1D1D1", "#7A7A7A"] },
                    markings: $scope.gcMarkings
                },
                zoom: { interactive: true }, // flot.navigate
                pan: { interactive: true } // flot.navigate
            }
        );
    }

    function presentationZoomPercents() {
        var overPan = 0;
        if($scope.xMinDisplay < $scope.xMinData) {
            // positive value for left overpan
            overPan = $scope.xMinData - $scope.xMinDisplay;
        }
        if($scope.xMaxDisplay > $scope.xMaxData) {
            // negative value for right overpan
            overPan = $scope.xMaxDisplay - $scope.xMaxData;
        }

        var offsetAbs = ($scope.xMinDisplay - $scope.xMinData);
        if(overPan < 0) {
            offsetAbs -= overPan;
        }
        var visibleAbs = $scope.xMaxDisplay - $scope.xMinDisplay - Math.abs(overPan);

        var dataRange = $scope.xMaxData - $scope.xMinData;
        return {
            percentOffset: offsetAbs  / dataRange * 100,
            percentVisible: visibleAbs  / dataRange * 100
        };
    }

    $scope.getZoomMinPercent = function() {
        return presentationZoomPercents().percentOffset;
    };
    $scope.getZoomVisiblePercent = function() {
        return presentationZoomPercents().percentVisible;
    };

    $scope.zoomIn = function() {
        plot.zoom();
    };
    $scope.zoomOut = function() {
        plot.zoomOut();
    };
    $scope.zoomReset = function() {
        plot.getAxes().xaxis.min = $scope.xMinData;
        plot.getAxes().xaxis.max = $scope.xMaxData;
        $scope.xMinDisplay = $scope.xMinData;
        $scope.xMaxDisplay = $scope.xMaxData;
        doPlot();
    };

    function refreshZoom(evt, plot) {
        $scope.safeApply(function() {
            var xaxis = plot.getAxes().xaxis;
            $scope.xMinDisplay = xaxis.min;
            $scope.xMaxDisplay = xaxis.max;
        });
    }

    //TODO limit zoom, limit pan
    $('#mem-gc-placeholder')
        .bind('plotzoom', refreshZoom)
        .bind('plotpan', refreshZoom);

    (function() {
        var previousPoint = null;

        function tooltipFor(item) {
            for(var i=0; i<$scope.gcs.length; i++) {
                var gc = $scope.gcs[i];
                if(gc.startMillis !== item.datapoint[0]) { //TODO is there a better way to do this?
                    continue;
                }
                //TODO layout of tool tip
                //TODO relative change of used memory per memgc kind
                //TODO *committed* memory (+ info if changed)
                return 'cause: ' + gc.cause + '
' +
                    'type: ' + gc.type + '
' +
                    'algorithm: ' + gc.algorithm + '
' +
                    'duration: ' + gc.durationNanos + 'ns';
            }
            return '';
        }

        $('#mem-gc-placeholder').bind("plothover", function (event, pos, item) {
            if (item) {
                if (previousPoint != item.dataIndex) {
                    previousPoint = item.dataIndex;

                    $("#tooltip").remove();

                    var x = item.datapoint[0];
                    var y = item.datapoint[1];

//                    var text = 'moin moin: ' + item.series.label;

                    showTooltip(item.pageX, item.pageY, tooltipFor(item));
//                        months[x-  1] + "
" + "" + y + " (" + item.series.label + ")");
                }
            }
            else {
                $("#tooltip").remove();
                previousPoint = null;
            }
        });

        //TODO nicer styling, move styling to CSS file
        function showTooltip(x, y, contents) {
            $('
' + contents + '
').css({
                position: 'absolute',
                display: 'none',
                top: y + 5,
                left: x + 20,
                border: '2px solid #4572A7',
                padding: '2px',
                size: '10',
                'background-color': '#fff',
                opacity: 0.90
            }).appendTo("body").fadeIn(200);
        }
    }());
});

<commit_msg>Reorder GC View<commit_after>
angular.module('NSysMonApp').controller('CtrlMemGc', function($scope, $log, Rest) {
    $('.btn').tooltip({
        container: 'body',
        html: true
    });

    //TODO display committed and maximum memory
    //TODO get 'current' memory consumption in addition to GC requests
    //TODO tool tip: left or right, depending on x coordinate

    $scope.safeApply = function(fn) {
        var phase = this.$root.$$phase;
        if(phase == '$apply' || phase == '$digest') {
            if(fn && (typeof(fn) === 'function')) {
                fn();
            }
        } else {
            this.$apply(fn);
        }
    };

    $scope.showFullGcMarkers = true;
    $scope.$watch('showFullGcMarkers', function() {
        if($scope.gcs) {
            $scope.dataAsMap['_full_'].points.show = $scope.showFullGcMarkers;
            extractGcMarkings($scope.gcs);
            doPlot();
        }
    });

    $scope.showOtherGcMarkers = false;
    $scope.$watch('showOtherGcMarkers', function() {
        if($scope.gcs) {
            extractGcMarkings($scope.gcs);
            doPlot();
        }
    });

    $scope.showLegend = true;
    $scope.$watch('showLegend', function() {
        if($scope.gcs) {
            doPlot();
        }
    });

    function endMillis(gc) {
        return gc.durationNanos < 1000*1000 ? gc.startMillis : (gc.startMillis + gc.durationNanos / 1000 / 1000);
    }

    function isFullGc(gc) {
        return gc.type.indexOf(' major ') !== -1;
    }

    function extractGcMarkings(gcs) {
        $scope.gcMarkings = [];

        for(var i=0; i<gcs.length; i++) {
            var gc = gcs[i];
            if(isFullGc(gc) && $scope.showFullGcMarkers) {
                $scope.gcMarkings.push({color: 'rgba(0,0,100,.8)', lineWidth: 1, xaxis: {from: gc.startMillis, to: endMillis(gc)}});
            }
            if(! isFullGc(gc) && $scope.showOtherGcMarkers) {
                $scope.gcMarkings.push({color: 'rgba(50,50,150,.7)', lineWidth: 1, xaxis: {from: gc.startMillis, to: endMillis(gc)}});
            }
        }
    }

    function initFromResponse(data) {
        $scope.gcs = data.gcs;

        $scope.startTime = undefined;
        if(data.gcs && data.gcs.length) {
            $scope.startTime = new Date(data.gcs[0].startMillis);
        }
        $scope.endTime = new Date();
        $scope.dataSets = [];
        $scope.gcMarkings = [];

        function extractDataAsMap () {
            var result = {};

            if(data.gcs && data.gcs.length) {
                $scope.xMinData = data.gcs[0].startMillis;
            }
            for(var i=0; i<data.gcs.length; i++) {
                var gc = data.gcs[i];

                for(var memKind in gc.mem) {
                    if(!gc.mem.hasOwnProperty(memKind)) continue;
                    if(! result[memKind]) {
                        result[memKind] = {
                            label: memKind,
                            hoverable: false,
                            data: []
                        };
                    }

                    var end = endMillis(gc);
                    $scope.xMaxData = end;
                    result[memKind].data.push([gc.startMillis, gc.mem[memKind].usedBefore / 1024 / 1024]);
                    result[memKind].data.push([end, gc.mem[memKind].usedAfter / 1024 / 1024]);
                }
                if(!result['_full_']) {
                    result['_full_'] = {
                        label: '_full_',
                        data: [],
                        lines: {show: false},
                        color: 'rgb(0,0,100)',
                        points: {show: true, radius: 7, fill: true, fillColor: 'rgb(100, 100, 200)'}
                    }
                }
                if(isFullGc(gc)) {
                    result['_full_'].data.push([gc.startMillis, 0]);
                }
            }
            $scope.xMinDisplay = $scope.xMinData;
            $scope.xMaxDisplay = $scope.xMaxData;

            return result;
        }

        function sortedMemKinds(dataAsMap) {
            var result = [];
            for(var memKind in dataAsMap) {
                if(!dataAsMap.hasOwnProperty(memKind)) continue;
                result.push(memKind);
            }
            result.sort(function(a,b) {
                var aOrder = memKindSortOrder[a];
                var bOrder = memKindSortOrder[b];

                if(aOrder && bOrder) return aOrder - bOrder;
                if(!aOrder) return 1;
                if(!bOrder) return -1;
                return a < b ? -1 : 1;
            });

            return result;
        }

        if(data.gcs && data.gcs.length) {
            $scope.dataAsMap = extractDataAsMap();
            var memKinds = sortedMemKinds($scope.dataAsMap);

            $scope.dataSets = [];
            for(var i=0; i<memKinds.length; i++) {
                $scope.dataSets.push($scope.dataAsMap[memKinds[i]]);
            }

            extractGcMarkings(data.gcs);
        }
    }

    var memKindSortOrder = {
        //'Metaspace' : 1,
        //'Compressed Class Space' : 2,
        //'G1 Old Gen': 3,
        //'G1 Survivor Space': 4,
        //'G1 Eden Space': 5,
        'Compressed Class Space' : 1,
        'Metaspace' : 2,
        'G1 Old Gen': 3,
        'PS Old Gen': 4,
        'G1 Survivor Space': 5,
        'PS Survivor Space': 6,
        'G1 Eden Space': 7,
        'PS Eden Space': 8,
        '_full_': 10
    };

    function sendCommand(cmd) {
        Rest.call(cmd, function(data) {
            initFromResponse(data);
            doPlot();
        });
    }

    $scope.refresh = function() {
        sendCommand('getData');
    };

    $scope.refresh();

    var plot;
    function doPlot() {
        plot = $.plot(
            '#mem-gc-placeholder',
            $scope.dataSets,
            {
                legend: {
                    show: $scope.showLegend,
                    position: 'ne',
                    backgroundOpacity: .7,
                    labelFormatter: function(label) {return label.charAt(0) === '_' ? null : label;}
                },
                xaxis: {
                    mode: 'time',
                    timezone: 'browser'
                },
                yaxis: {
                    axisLabel: 'Memory Size (MB)',
                    zoomRange: false, // flot.navigate
                    panRange: false, // flot.navigate
                    transform: function(v) {return v;}
                },
                series: {stack: true},
//                colors: [0, 1, 2, 3, 4, 5, 6],
                lines: {
                    lineWidth: 1,
                    fill: true
                },
                grid: {
                    hoverable: true,
                    mouseActiveRadius: 15,
//                    backgroundColor: { colors: ["#D1D1D1", "#7A7A7A"] },
                    markings: $scope.gcMarkings
                },
                zoom: { interactive: true }, // flot.navigate
                pan: { interactive: true } // flot.navigate
            }
        );
    }

    function presentationZoomPercents() {
        var overPan = 0;
        if($scope.xMinDisplay < $scope.xMinData) {
            // positive value for left overpan
            overPan = $scope.xMinData - $scope.xMinDisplay;
        }
        if($scope.xMaxDisplay > $scope.xMaxData) {
            // negative value for right overpan
            overPan = $scope.xMaxDisplay - $scope.xMaxData;
        }

        var offsetAbs = ($scope.xMinDisplay - $scope.xMinData);
        if(overPan < 0) {
            offsetAbs -= overPan;
        }
        var visibleAbs = $scope.xMaxDisplay - $scope.xMinDisplay - Math.abs(overPan);

        var dataRange = $scope.xMaxData - $scope.xMinData;
        return {
            percentOffset: offsetAbs  / dataRange * 100,
            percentVisible: visibleAbs  / dataRange * 100
        };
    }

    $scope.getZoomMinPercent = function() {
        return presentationZoomPercents().percentOffset;
    };
    $scope.getZoomVisiblePercent = function() {
        return presentationZoomPercents().percentVisible;
    };

    $scope.zoomIn = function() {
        plot.zoom();
    };
    $scope.zoomOut = function() {
        plot.zoomOut();
    };
    $scope.zoomReset = function() {
        plot.getAxes().xaxis.min = $scope.xMinData;
        plot.getAxes().xaxis.max = $scope.xMaxData;
        $scope.xMinDisplay = $scope.xMinData;
        $scope.xMaxDisplay = $scope.xMaxData;
        doPlot();
    };

    function refreshZoom(evt, plot) {
        $scope.safeApply(function() {
            var xaxis = plot.getAxes().xaxis;
            $scope.xMinDisplay = xaxis.min;
            $scope.xMaxDisplay = xaxis.max;
        });
    }

    //TODO limit zoom, limit pan
    $('#mem-gc-placeholder')
        .bind('plotzoom', refreshZoom)
        .bind('plotpan', refreshZoom);

    (function() {
        var previousPoint = null;

        function tooltipFor(item) {
            for(var i=0; i<$scope.gcs.length; i++) {
                var gc = $scope.gcs[i];
                if(gc.startMillis !== item.datapoint[0]) { //TODO is there a better way to do this?
                    continue;
                }
                //TODO layout of tool tip
                //TODO relative change of used memory per memgc kind
                //TODO *committed* memory (+ info if changed)
                return 'cause: ' + gc.cause + '
' +
                    'type: ' + gc.type + '
' +
                    'algorithm: ' + gc.algorithm + '
' +
                    'duration: ' + gc.durationNanos + 'ns';
            }
            return '';
        }

        $('#mem-gc-placeholder').bind("plothover", function (event, pos, item) {
            if (item) {
                if (previousPoint != item.dataIndex) {
                    previousPoint = item.dataIndex;

                    $("#tooltip").remove();

                    var x = item.datapoint[0];
                    var y = item.datapoint[1];

//                    var text = 'moin moin: ' + item.series.label;

                    showTooltip(item.pageX, item.pageY, tooltipFor(item));
//                        months[x-  1] + "
" + "" + y + " (" + item.series.label + ")");
                }
            }
            else {
                $("#tooltip").remove();
                previousPoint = null;
            }
        });

        //TODO nicer styling, move styling to CSS file
        function showTooltip(x, y, contents) {
            $('
' + contents + '
').css({
                position: 'absolute',
                display: 'none',
                top: y + 5,
                left: x + 20,
                border: '2px solid #4572A7',
                padding: '2px',
                size: '10',
                'background-color': '#fff',
                opacity: 0.90
            }).appendTo("body").fadeIn(200);
        }
    }());
});

<|endoftext|>


<commit_before>// @flow

import * as React from 'react';
import { Text, Alert, ActivityIndicator, View } from 'react-native';

import {
  changeThreadSettingsActionTypes,
  changeThreadSettings,
} from 'lib/actions/thread-actions';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors';
import type { LoadingStatus } from 'lib/types/loading-types';
import {
  type ThreadInfo,
  type UpdateThreadRequest,
  type ChangeThreadSettingsPayload,
  threadTypes,
} from 'lib/types/thread-types';
import {
  type DispatchActionPromise,
  useServerCall,
  useDispatchActionPromise,
} from 'lib/utils/action-utils';

import Button from '../../components/button.react';
import { useSelector } from '../../redux/redux-utils';
import { type Colors, useColors, useStyles } from '../../themes/colors';
import type { ViewStyle } from '../../types/styles';

type BaseProps = {|
  +threadInfo: ThreadInfo,
  +buttonStyle: ViewStyle,
|};
type Props = {|
  ...BaseProps,
  // Redux state
  +loadingStatus: LoadingStatus,
  +colors: Colors,
  +styles: typeof unboundStyles,
  // Redux dispatch functions
  +dispatchActionPromise: DispatchActionPromise,
  // async functions that hit server APIs
  +changeThreadSettings: (
    request: UpdateThreadRequest,
  ) => Promise<ChangeThreadSettingsPayload>,
|};
class ThreadSettingsPromoteSubthread extends React.PureComponent<Props> {
  render() {
    const {
      panelIosHighlightUnderlay,
      panelForegroundSecondaryLabel,
    } = this.props.colors;
    const loadingIndicator =
      this.props.loadingStatus === 'loading' ? (
        <ActivityIndicator size="small" color={panelForegroundSecondaryLabel} />
      ) : null;
    return (
      <View style={this.props.styles.container}>
        <Button
          onPress={this.onPress}
          style={[this.props.styles.button, this.props.buttonStyle]}
          iosFormat="highlight"
          iosHighlightUnderlayColor={panelIosHighlightUnderlay}
        >
          <Text style={this.props.styles.text}>Promote to subthread...</Text>
          {loadingIndicator}
        </Button>
      </View>
    );
  }

  onPress = () => {
    this.props.dispatchActionPromise(
      changeThreadSettingsActionTypes,
      this.changeThreadSettings(),
    );
  };

  async changeThreadSettings() {
    const threadID = this.props.threadInfo.id;
    try {
      return await this.props.changeThreadSettings({
        threadID,
        changes: { type: threadTypes.CHAT_NESTED_OPEN },
      });
    } catch (e) {
      Alert.alert('Unknown error', 'Uhh... try again?', undefined, {
        cancelable: true,
      });
      throw e;
    }
  }
}

const unboundStyles = {
  button: {
    flexDirection: 'row',
    paddingHorizontal: 12,
    paddingVertical: 10,
  },
  container: {
    backgroundColor: 'panelForeground',
    paddingHorizontal: 12,
  },
  text: {
    color: 'panelForegroundSecondaryLabel',
    flex: 1,
    fontSize: 16,
  },
};

const loadingStatusSelector = createLoadingStatusSelector(
  changeThreadSettingsActionTypes,
);

export default React.memo<BaseProps>(
  function ConnectedThreadSettingsPromoteSubthread(props: BaseProps) {
    const loadingStatus = useSelector(loadingStatusSelector);
    const colors = useColors();
    const styles = useStyles(unboundStyles);
    const dispatchActionPromise = useDispatchActionPromise();
    const callChangeThreadSettings = useServerCall(changeThreadSettings);
    return (
      <ThreadSettingsPromoteSubthread
        {...props}
        loadingStatus={loadingStatus}
        colors={colors}
        styles={styles}
        dispatchActionPromise={dispatchActionPromise}
        changeThreadSettings={callChangeThreadSettings}
      />
    );
  },
);
<commit_msg>[native] Fix ThreadSettingsPromoteSidebar name<commit_after>// @flow

import * as React from 'react';
import { Text, Alert, ActivityIndicator, View } from 'react-native';

import {
  changeThreadSettingsActionTypes,
  changeThreadSettings,
} from 'lib/actions/thread-actions';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors';
import type { LoadingStatus } from 'lib/types/loading-types';
import {
  type ThreadInfo,
  type UpdateThreadRequest,
  type ChangeThreadSettingsPayload,
  threadTypes,
} from 'lib/types/thread-types';
import {
  type DispatchActionPromise,
  useServerCall,
  useDispatchActionPromise,
} from 'lib/utils/action-utils';

import Button from '../../components/button.react';
import { useSelector } from '../../redux/redux-utils';
import { type Colors, useColors, useStyles } from '../../themes/colors';
import type { ViewStyle } from '../../types/styles';

type BaseProps = {|
  +threadInfo: ThreadInfo,
  +buttonStyle: ViewStyle,
|};
type Props = {|
  ...BaseProps,
  // Redux state
  +loadingStatus: LoadingStatus,
  +colors: Colors,
  +styles: typeof unboundStyles,
  // Redux dispatch functions
  +dispatchActionPromise: DispatchActionPromise,
  // async functions that hit server APIs
  +changeThreadSettings: (
    request: UpdateThreadRequest,
  ) => Promise<ChangeThreadSettingsPayload>,
|};
class ThreadSettingsPromoteSidebar extends React.PureComponent<Props> {
  render() {
    const {
      panelIosHighlightUnderlay,
      panelForegroundSecondaryLabel,
    } = this.props.colors;
    const loadingIndicator =
      this.props.loadingStatus === 'loading' ? (
        <ActivityIndicator size="small" color={panelForegroundSecondaryLabel} />
      ) : null;
    return (
      <View style={this.props.styles.container}>
        <Button
          onPress={this.onPress}
          style={[this.props.styles.button, this.props.buttonStyle]}
          iosFormat="highlight"
          iosHighlightUnderlayColor={panelIosHighlightUnderlay}
        >
          <Text style={this.props.styles.text}>Promote to subthread...</Text>
          {loadingIndicator}
        </Button>
      </View>
    );
  }

  onPress = () => {
    this.props.dispatchActionPromise(
      changeThreadSettingsActionTypes,
      this.changeThreadSettings(),
    );
  };

  async changeThreadSettings() {
    const threadID = this.props.threadInfo.id;
    try {
      return await this.props.changeThreadSettings({
        threadID,
        changes: { type: threadTypes.CHAT_NESTED_OPEN },
      });
    } catch (e) {
      Alert.alert('Unknown error', 'Uhh... try again?', undefined, {
        cancelable: true,
      });
      throw e;
    }
  }
}

const unboundStyles = {
  button: {
    flexDirection: 'row',
    paddingHorizontal: 12,
    paddingVertical: 10,
  },
  container: {
    backgroundColor: 'panelForeground',
    paddingHorizontal: 12,
  },
  text: {
    color: 'panelForegroundSecondaryLabel',
    flex: 1,
    fontSize: 16,
  },
};

const loadingStatusSelector = createLoadingStatusSelector(
  changeThreadSettingsActionTypes,
);

export default React.memo<BaseProps>(
  function ConnectedThreadSettingsPromoteSidebar(props: BaseProps) {
    const loadingStatus = useSelector(loadingStatusSelector);
    const colors = useColors();
    const styles = useStyles(unboundStyles);
    const dispatchActionPromise = useDispatchActionPromise();
    const callChangeThreadSettings = useServerCall(changeThreadSettings);
    return (
      <ThreadSettingsPromoteSidebar
        {...props}
        loadingStatus={loadingStatus}
        colors={colors}
        styles={styles}
        dispatchActionPromise={dispatchActionPromise}
        changeThreadSettings={callChangeThreadSettings}
      />
    );
  },
);
<|endoftext|>


<commit_before>var common = require("./common.js");

describe('relations', function() {

    function addRelation() {
        return element.all(by.tagName('relation-picker-group')).first()
            .element(by.css('.circular-button.add-relation')).click();
    }

    function getFirstRelationOfGroup(groupIndex) {
        return element.all(by.tagName('relation-picker-group')).get(groupIndex)
            .all(by.tagName('relation-picker')).first();
    }

    function getSuggestion(relation, index) {
        return relation.all(by.css('.suggestion')).get(index);
    }

    function scrollDown() {
        return browser.executeScript('window.scrollTo(0,100);');
    }

    function scrollUp() {
        return browser.executeScript('window.scrollTo(0,0);');
    }

    function getRelationButton(relation, index) {
        return relation.all(by.tagName('button')).get(index);
    }

    beforeEach(function(){
        browser.get('/');
    });

    it('should create a new relation and the corresponding inverse relation', function() {
        // expect(getFirstRelationOfGroup(0).isPresent()).toBe(false); known not to work on ci

        common.createObject("o1")
            .then(common.createObject("o2"))
            .then(scrollDown)
            .then(addRelation)

            .then(function() {
                expect(getFirstRelationOfGroup(0).isPresent()).toBe(true);
                // expect(getSuggestion(getFirstRelationOfGroup(0), 0).isPresent()).toBe(false); known not to work on ci
                return common.typeIn(getFirstRelationOfGroup(0).element(by.tagName("input")), "o1");
            })
            .then(function() {
                expect(getSuggestion(getFirstRelationOfGroup(0), 0).isPresent()).toBe(true);
                return getSuggestion(getFirstRelationOfGroup(0), 0).click();
            })
            .then(function() {
                expect(getRelationButton(getFirstRelationOfGroup(0), 0).isPresent()).toBe(true);
                expect(getRelationButton(getFirstRelationOfGroup(0), 0).element(by.tagName("span")).getText())
                    .toEqual("o1");
                return scrollUp().then(common.saveObject);
            })
            .then(common.selectObject(1))
            .then(scrollDown)
            .then(function() {
                expect(getFirstRelationOfGroup(1).isPresent()).toBe(true);
                expect(getRelationButton(getFirstRelationOfGroup(1), 0).isPresent()).toBe(true);
                expect(getRelationButton(getFirstRelationOfGroup(1), 0).element(by.tagName("span")).getText())
                    .toEqual("o2");
            });
    });

});
<commit_msg>Resolve merge conflict.<commit_after>var common = require("./common.js");

describe('relations', function() {

    function addRelation() {
        return element.all(by.tagName('relation-picker-group')).first()
            .element(by.css('.circular-button.add-relation')).click();
    }

    function getFirstRelationOfGroup(groupIndex) {
        return element.all(by.tagName('relation-picker-group')).get(groupIndex)
            .all(by.tagName('relation-picker')).first();
    }

    function getSuggestion(relation, index) {
        return relation.all(by.css('.suggestion')).get(index);
    }

    function scrollDown() {
        return browser.executeScript('window.scrollTo(0,200);');
    }

    function scrollUp() {
        return browser.executeScript('window.scrollTo(0,0);');
    }

    function getRelationButton(relation, index) {
        return relation.all(by.tagName('button')).get(index);
    }

    beforeEach(function(){
        browser.get('/');
    });

    it('should create a new relation and the corresponding inverse relation', function() {
        // expect(getFirstRelationOfGroup(0).isPresent()).toBe(false); known not to work on ci

        common.createObject("o1")
            .then(common.createObject("o2"))
            .then(scrollDown)
            .then(addRelation)

            .then(function() {
                expect(getFirstRelationOfGroup(0).isPresent()).toBe(true);
                // expect(getSuggestion(getFirstRelationOfGroup(0), 0).isPresent()).toBe(false); known not to work on ci
                return common.typeIn(getFirstRelationOfGroup(0).element(by.tagName("input")), "o1");
            })
            .then(function() {
                expect(getSuggestion(getFirstRelationOfGroup(0), 0).isPresent()).toBe(true);
                return getSuggestion(getFirstRelationOfGroup(0), 0).click();
            })
            .then(function() {
                expect(getRelationButton(getFirstRelationOfGroup(0), 0).isPresent()).toBe(true);
                expect(getRelationButton(getFirstRelationOfGroup(0), 0).element(by.tagName("span")).getText())
                    .toEqual("o1");
                return scrollUp().then(common.saveObject);
            })
            .then(common.selectObject(1))
            .then(scrollDown)
            .then(function() {
                expect(getFirstRelationOfGroup(1).isPresent()).toBe(true);
                expect(getRelationButton(getFirstRelationOfGroup(1), 0).isPresent()).toBe(true);
                expect(getRelationButton(getFirstRelationOfGroup(1), 0).element(by.tagName("span")).getText())
                    .toEqual("o2");
            });
    });

});
<|endoftext|>


<commit_before>var childProcess = require('child_process')
  , mkdirp       = require('mkdirp')
  , config       = require('moonraker').config
  , glob         = require('glob')
  , fs           = require('fs')
  , path         = require('path')
  , rimraf       = require('rimraf')
  , builder      = require('../lib/html-reporter/builder')

var workingDir = path.join(config.featuresDir, 'temp');

if (fs.existsSync(workingDir)) {
  rimraf.sync(workingDir);
}

mkdirp.sync(path.join(config.resultsDir, 'screenshots'));

var features = glob.sync(config.featuresDir + "/**/*.feature");
var queues = split(features, config.threads);
var pid = null;

queues.forEach(function(queue) {

  var thread = childProcess.fork('./node_modules/moonraker/lib/env/mocha');
  pid = thread.pid.toString();
  mkdirp.sync(path.join(config.featuresDir,'temp', pid));

  queue.forEach(function(featureFile) {
    filename = featureFile.split('/').pop();
    fs.writeFileSync(path.join(config.featuresDir, 'temp', pid, filename),
      fs.readFileSync(featureFile));
  });

  thread.send({ mocha: true });
});

process.on('exit', function() {
  if (config.reporter == 'html') {
    builder.createHtmlReport();
  }
  rimraf.sync(workingDir);
});

function split(features, threads) {
  var len = features.length, queues = [], i = 0;
  while (i < len) {
    var size = Math.ceil((len - i) / threads--);
    queues.push(features.slice(i, i + size));
    i += size;
  }
  return queues;
}
<commit_msg>Command line args now passed to child processes properly!<commit_after>var childProcess = require('child_process')
  , mkdirp       = require('mkdirp')
  , config       = require('moonraker').config
  , glob         = require('glob')
  , fs           = require('fs')
  , path         = require('path')
  , rimraf       = require('rimraf')
  , builder      = require('../lib/html-reporter/builder')

var workingDir = path.join(config.featuresDir, 'temp');

if (fs.existsSync(workingDir)) {
  rimraf.sync(workingDir);
}

mkdirp.sync(path.join(config.resultsDir, 'screenshots'));

var features = glob.sync(config.featuresDir + "/**/*.feature");
var queues = split(features, config.threads);
var pid = null;

queues.forEach(function(queue) {

  var thread = childProcess.fork('./node_modules/moonraker/lib/env/mocha', process.argv);
  pid = thread.pid.toString();
  mkdirp.sync(path.join(config.featuresDir,'temp', pid));

  queue.forEach(function(featureFile) {
    filename = featureFile.split('/').pop();
    fs.writeFileSync(path.join(config.featuresDir, 'temp', pid, filename),
      fs.readFileSync(featureFile));
  });

  thread.send({ mocha: true });
});

process.on('exit', function() {
  if (config.reporter == 'html') {
    builder.createHtmlReport();
  }
  rimraf.sync(workingDir);
});

function split(features, threads) {
  var len = features.length, queues = [], i = 0;
  while (i < len) {
    var size = Math.ceil((len - i) / threads--);
    queues.push(features.slice(i, i + size));
    i += size;
  }
  return queues;
}
<|endoftext|>


<commit_before>var http = require('http');

///////////////////////////////////////////
// Prerequisites for running the server. //
///////////////////////////////////////////

// Obtain local ip address to create an appropriate server.

var os = require('os');
var ifaces = os.networkInterfaces();

var myHost = null;

Object.keys(ifaces).forEach(function (ifname) {
    ifaces[ifname].forEach(function (iface) {
        if (iface.internal || iface.family == 'IPv6')
            return;
        else
            myHost = iface.address;
    });
});

// TODO: Find an open port to use
port = 8099;

var dataObj = null;

server = http.createServer( function(req, res) {
    if (req.method == 'POST')
    {
        res.writeHead(200, {'Content-Type': 'text/html'});

        var body = '';
        req.on('data', function (data) {
            body += data;
        });

        req.on('end', function () {
            dataObj = JSON.parse(body);
        });
    }
    else
    {
        res.writeHead(200, {'Content-Type': 'application/json'});

        if (dataObj)
        {
            res.end(JSON.stringify(dataObj));
        }
        else
        {
            res.end(JSON.stringify({ data: null }));
        }
    }
});

try {
    // Listen to both external ips and internal ips
    // External ip used by Device connected with Pebble
    server.listen(port, myHost);

    // Internal ip used by CSGO to connect.
    server.listen(port);

    // Verbose statements
    console.log('Listening at http://' + myHost + ':' + port);
    console.log('Please go to the pebble watch settings and insert: http://' + myHost + ':' + port);
}
catch (e)
{
    console.log('Could not obtain an open port at ' + port + '. Please try again.');
}
<commit_msg>added json filtering for server<commit_after>var http = require('http');

///////////////////////////////////////////
// Prerequisites for running the server. //
///////////////////////////////////////////

// Obtain local ip address to create an appropriate server.

var os = require('os');
var ifaces = os.networkInterfaces();

var myHost = null;

Object.keys(ifaces).forEach(function (ifname) {
    ifaces[ifname].forEach(function (iface) {
        if (iface.internal || iface.family == 'IPv6')
            return;
        else
            myHost = iface.address;
    });
});

/////////////////////////
// Filtering functions //
/////////////////////////

function filterCSGOData(dataObj)
{
    var dataMap = {
	provider : {},
	map : {},
	round : {},
	/*
	  As of now, not required...maybe in the future for gui fanciness
	  player :
	*/
    };

    if (dataObj.provider)
    {
	dataMap.provider["timestamp"] = dataObj.provider.timestamp || null;
    }
    if (dataObj.map)
    {
	dataMap.map["mode"] = dataObj.map.mode || null;
    }

    if (dataObj.round)
    {
	dataMap.round["phase"] = dataMap.round.phase || null;
	dataMap.round["bomb"] = dataMap.round.bomb || null;
    }

    console.log(dataMap);
    return dataMap;
}

////////////////////
// Server Portion //
////////////////////

// TODO: Find an open port to use
port = 8099;

var dataObj = null;

server = http.createServer( function(req, res) {
    if (req.method == 'POST')
    {
        res.writeHead(200, {'Content-Type': 'text/html'});

        var body = '';
        req.on('data', function (data) {
            body += data;
        });

        req.on('end', function () {
            dataObj = JSON.parse(body);
        });
    }
    else
    {
        res.writeHead(200, {'Content-Type': 'application/json'});

        if (dataObj)
        {
            res.end(JSON.stringify(filterCSGOData(dataObj)));
        }
        else
        {
            res.end(JSON.stringify({ data: null }));
        }
    }
});

try {
    // Listen to both external ips and internal ips
    // External ip used by Device connected with Pebble
    server.listen(port, myHost);

    // Internal ip used by CSGO to connect.
    server.listen(port);

    // Verbose statements
    console.log('Listening at http://' + myHost + ':' + port);
    console.log('Please go to the pebble watch settings and insert: http://' + myHost + ':' + port);
}
catch (e)
{
    console.log('Could not obtain an open port at ' + port + '. Please try again.');
}
<|endoftext|>


<commit_before>require.config({
    // 定义文件、路径的简写
    paths: {
        'tmpl': 'base/require.tmpl',
        'jquery': 'base/jquery',
        'underscore': 'base/underscore',
        'Backbone': 'base/Backbone',
        'html': '../html'
    },
    // 对没有定义为AMD模块的第三方类库框架，在此补充定义该模块的依赖和输出
    shim: {
        'underscore': {
            exports: '_'
        },
        'Backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        }
    }
});

require([
    'controller'
], function(controller){
    // TODO: 判断是否高级浏览器；登陆

    controller.init();
});
<commit_msg>Define Backbone.Relational module<commit_after>require.config({
    // 定义文件、路径的简写
    paths: {
        'tmpl': 'base/require.tmpl',
        'jquery': 'base/jquery',
        'underscore': 'base/underscore',
        'Backbone': 'base/Backbone',
        'Backbone.Relational': 'base/Backbone.Relational',
        'html': '../html'
    },
    // 对没有定义为AMD模块的第三方类库框架，在此补充定义该模块的依赖和输出
    shim: {
        'underscore': {
            exports: '_'
        },
        'Backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        },
        'Backbone.Relational': {
            deps: ['Backbone'],
            exports: 'Backbone'
        }
    }
});

require([
    'controller'
], function(controller){
    // TODO: 判断是否高级浏览器；登陆

    controller.init();
});
<|endoftext|>


<commit_before>/**
 * @author aniero / https://github.com/aniero
 */
var DiagonalMovement = require('../core/DiagonalMovement');
var JPFNeverMoveDiagonally = require('./JPFNeverMoveDiagonally');
var JPFAlwaysMoveDiagonally = require('./JPFAlwaysMoveDiagonally');
var JPFMoveDiagonallyIfNoObstacles = require('./JPFMoveDiagonallyIfNoObstacles');
var JPFMoveDiagonallyIfAtMostOneObstacle = require('./JPFMoveDiagonallyIfAtMostOneObstacle');

/**
 * Path finder using the Jump Point Search algorithm
 * @param {object} opt
 * @param {function} opt.heuristic Heuristic function to estimate the distance
 *     (defaults to manhattan).
 * @param {DiagonalMovement} opt.diagonalMovement Condition under which diagonal
 *      movement will be allowed.
 */
function JumpPointFinder(opt) {
    if (opt.diagonalMovement === DiagonalMovement.Never) {
        return new JPFNeverMoveDiagonally(opt);
    } else if (opt.diagonalMovement === DiagonalMovement.Always) {
        return new JPFAlwaysMoveDiagonally(opt);
    } else if (opt.diagonalMovement === DiagonalMovement.OnlyWhenNoObstacles) {
        return new JPFMoveDiagonallyIfNoObstacles(opt);
    } else {
        return new JPFMoveDiagonallyIfAtMostOneObstacle(opt);
    }
}

module.exports = JumpPointFinder;
<commit_msg>Fix exception on missing options object<commit_after>/**
 * @author aniero / https://github.com/aniero
 */
var DiagonalMovement = require('../core/DiagonalMovement');
var JPFNeverMoveDiagonally = require('./JPFNeverMoveDiagonally');
var JPFAlwaysMoveDiagonally = require('./JPFAlwaysMoveDiagonally');
var JPFMoveDiagonallyIfNoObstacles = require('./JPFMoveDiagonallyIfNoObstacles');
var JPFMoveDiagonallyIfAtMostOneObstacle = require('./JPFMoveDiagonallyIfAtMostOneObstacle');

/**
 * Path finder using the Jump Point Search algorithm
 * @param {object} opt
 * @param {function} opt.heuristic Heuristic function to estimate the distance
 *     (defaults to manhattan).
 * @param {DiagonalMovement} opt.diagonalMovement Condition under which diagonal
 *      movement will be allowed.
 */
function JumpPointFinder(opt) {
    opt = opt || {};
    if (opt.diagonalMovement === DiagonalMovement.Never) {
        return new JPFNeverMoveDiagonally(opt);
    } else if (opt.diagonalMovement === DiagonalMovement.Always) {
        return new JPFAlwaysMoveDiagonally(opt);
    } else if (opt.diagonalMovement === DiagonalMovement.OnlyWhenNoObstacles) {
        return new JPFMoveDiagonallyIfNoObstacles(opt);
    } else {
        return new JPFMoveDiagonallyIfAtMostOneObstacle(opt);
    }
}

module.exports = JumpPointFinder;
<|endoftext|>


<commit_before>import {Plugin, PluginKey} from "prosemirror-state"

export function addDeletedPartWidget(dom, view, getPos) {
    dom.classList.add('article-deleted')
    dom.insertAdjacentHTML(
        'beforeend',
        '

'
    )
    const removeButton = dom.lastElementChild
    removeButton.addEventListener('click', () => {
        const from = getPos(),
            to = from + view.state.doc.nodeAt(from).nodeSize,
            tr = view.state.tr
        tr.delete(from, to)
        tr.setMeta('filterFree', true)
        view.dispatch(tr)
    })
}

export class PartView {
    constructor(node, view, getPos) {
        this.node = node
        this.view = view
        this.getPos = getPos
        this.dom = document.createElement('div')
        this.dom.classList.add('article-part')
        this.dom.classList.add(`article-${this.node.type.name}`)
        this.dom.classList.add(`article-${this.node.attrs.id}`)
        if (node.attrs.hidden) {
            this.dom.dataset.hidden = true
        }
        if (node.attrs.deleted) {
            this.contentDOM = this.dom.appendChild(document.createElement('div'))
            addDeletedPartWidget(this.dom, view, getPos)
        } else {
            this.contentDOM = this.dom
        }
    }

    stopEvent() {
        return false
    }
}

const key = new PluginKey('documentTemplate')
export const documentTemplatePlugin = function(options) {
    return new Plugin({
        key,
        state: {
            init(_config, _state) {
                if (options.editor.docInfo.access_rights === 'write') {
                    this.spec.props.nodeViews['richtext_part'] = (node, view, getPos) => new PartView(
                        node,
                        view,
                        getPos
                    )
                    this.spec.props.nodeViews['heading_part'] = (node, view, getPos) => new PartView(
                        node,
                        view,
                        getPos
                    )
                    this.spec.props.nodeViews['table_part'] = (node, view, getPos) => new PartView(
                        node,
                        view,
                        getPos
                    )
                    // Tags and Contributors have node views defined in tag_input and contributor_input.
                }

                return {}
            },
            apply(tr, prev) {
                return prev
            }
        },
        props: {
            nodeViews: {}
        },
        filterTransaction: (tr, state) => {
            if (
                !tr.steps.length ||
                tr.getMeta('fixIds') ||
                tr.getMeta('remote') ||
                tr.getMeta('track') ||
                tr.getMeta('fromFootnote') ||
                tr.getMeta('filterFree') ||
                tr.getMeta('untracked') ||
                ['historyUndo', 'historyRedo'].includes(tr.getMeta('inputType'))
            ) {
                return true
            }
            if (state.doc.firstChild.childCount !== tr.doc.firstChild.childCount) {
                return false
            }
            let allowed = true

            let ranges = []

            tr.steps.forEach((step, index) => {
                ranges.push({from: step.from, to: step.to})
                ranges = ranges.map(range => ({from: tr.mapping.maps[index].map(range.from, -1), to: tr.mapping.maps[index].map(range.to, 1)}))
            })
            let allowedElements = false, allowedMarks = false

            ranges.forEach(range => tr.doc.nodesBetween(range.from, range.to, (node, pos, parent, index) => {
                if (parent===tr.doc.firstChild) {
                    allowedElements = node.attrs.elements ? node.attrs.elements.concat('table_row', 'table_cell', 'list_item', 'text') : false
                    allowedMarks = node.attrs.marks ? node.attrs.marks.concat('insertion', 'deletion', 'comment') : false
                    const oldNode = state.doc.firstChild.child(index)
                    if (
                        oldNode.type !== node.type ||
                        oldNode.attrs.id !== node.attrs.id ||
                        oldNode.attrs.title !== node.attrs.title ||
                        oldNode.attrs.locking !== node.attrs.locking ||
                        oldNode.attrs.language !== node.attrs.language ||
                        oldNode.attrs.elements !== node.attrs.elements ||
                        oldNode.attrs.marks !== node.attrs.marks ||
                        oldNode.attrs.language !== node.attrs.language ||
                        oldNode.attrs.item_title !== node.attrs.item_title ||
                        oldNode.attrs.optional !== node.attrs.optional ||
                        oldNode.attrs.help !== node.attrs.help
                    ) {
                        allowed = false
                    } else if (
                        node.type.name === 'table_part' &&
                        node.attrs.locking === 'header' &&
                        !node.firstChild.firstChild.eq(oldNode.firstChild.firstChild)
                    ) {
                        allowed = false
                    }
                    return true
                }
                if (pos < range.from) {
                    return true
                }
                if (node === tr.doc.firstChild) {
                    // block some settings changes
                    const oldNode = state.doc.firstChild
                    if (
                        oldNode.attrs.footnote_marks !== node.attrs.footnote_marks ||
                        oldNode.attrs.footnote_elements !== node.attrs.footnote_elements ||
                        oldNode.attrs.languages !== node.attrs.languages ||
                        oldNode.attrs.papersizes !== node.attrs.papersizes ||
                        oldNode.attrs.template !== node.attrs.template ||
                        !node.attrs.papersizes.includes(node.attrs.papersize) ||
                        !node.attrs.languages.includes(node.attrs.language)
                    ) {
                        allowed = false
                        return false
                    } else {
                        allowed = true
                        return true
                    }
                }
                if (
                    allowedElements &&
                    !allowedElements.includes(node.type.name)
                ) {
                    allowed = false
                } else if (allowedMarks) {
                    node.marks.forEach(mark => {
                        if (!allowedMarks.includes(mark.type.name)) {
                            allowed = false
                        }
                    })
                }

            }))

            return allowed
        }
    })
}
<commit_msg>allow table headers<commit_after>import {Plugin, PluginKey} from "prosemirror-state"

export function addDeletedPartWidget(dom, view, getPos) {
    dom.classList.add('article-deleted')
    dom.insertAdjacentHTML(
        'beforeend',
        '

'
    )
    const removeButton = dom.lastElementChild
    removeButton.addEventListener('click', () => {
        const from = getPos(),
            to = from + view.state.doc.nodeAt(from).nodeSize,
            tr = view.state.tr
        tr.delete(from, to)
        tr.setMeta('filterFree', true)
        view.dispatch(tr)
    })
}

export class PartView {
    constructor(node, view, getPos) {
        this.node = node
        this.view = view
        this.getPos = getPos
        this.dom = document.createElement('div')
        this.dom.classList.add('article-part')
        this.dom.classList.add(`article-${this.node.type.name}`)
        this.dom.classList.add(`article-${this.node.attrs.id}`)
        if (node.attrs.hidden) {
            this.dom.dataset.hidden = true
        }
        if (node.attrs.deleted) {
            this.contentDOM = this.dom.appendChild(document.createElement('div'))
            addDeletedPartWidget(this.dom, view, getPos)
        } else {
            this.contentDOM = this.dom
        }
    }

    stopEvent() {
        return false
    }
}

const key = new PluginKey('documentTemplate')
export const documentTemplatePlugin = function(options) {
    return new Plugin({
        key,
        state: {
            init(_config, _state) {
                if (options.editor.docInfo.access_rights === 'write') {
                    this.spec.props.nodeViews['richtext_part'] = (node, view, getPos) => new PartView(
                        node,
                        view,
                        getPos
                    )
                    this.spec.props.nodeViews['heading_part'] = (node, view, getPos) => new PartView(
                        node,
                        view,
                        getPos
                    )
                    this.spec.props.nodeViews['table_part'] = (node, view, getPos) => new PartView(
                        node,
                        view,
                        getPos
                    )
                    // Tags and Contributors have node views defined in tag_input and contributor_input.
                }

                return {}
            },
            apply(tr, prev) {
                return prev
            }
        },
        props: {
            nodeViews: {}
        },
        filterTransaction: (tr, state) => {
            if (
                !tr.steps.length ||
                tr.getMeta('fixIds') ||
                tr.getMeta('remote') ||
                tr.getMeta('track') ||
                tr.getMeta('fromFootnote') ||
                tr.getMeta('filterFree') ||
                tr.getMeta('untracked') ||
                ['historyUndo', 'historyRedo'].includes(tr.getMeta('inputType'))
            ) {
                return true
            }
            if (state.doc.firstChild.childCount !== tr.doc.firstChild.childCount) {
                return false
            }
            let allowed = true

            let ranges = []

            tr.steps.forEach((step, index) => {
                ranges.push({from: step.from, to: step.to})
                ranges = ranges.map(range => ({from: tr.mapping.maps[index].map(range.from, -1), to: tr.mapping.maps[index].map(range.to, 1)}))
            })
            let allowedElements = false, allowedMarks = false

            ranges.forEach(range => tr.doc.nodesBetween(range.from, range.to, (node, pos, parent, index) => {
                if (parent===tr.doc.firstChild) {
                    allowedElements = node.attrs.elements ? node.attrs.elements.concat('table_row', 'table_cell', 'table_header', 'list_item', 'text') : false
                    allowedMarks = node.attrs.marks ? node.attrs.marks.concat('insertion', 'deletion', 'comment') : false
                    const oldNode = state.doc.firstChild.child(index)
                    if (
                        oldNode.type !== node.type ||
                        oldNode.attrs.id !== node.attrs.id ||
                        oldNode.attrs.title !== node.attrs.title ||
                        oldNode.attrs.locking !== node.attrs.locking ||
                        oldNode.attrs.language !== node.attrs.language ||
                        oldNode.attrs.elements !== node.attrs.elements ||
                        oldNode.attrs.marks !== node.attrs.marks ||
                        oldNode.attrs.language !== node.attrs.language ||
                        oldNode.attrs.item_title !== node.attrs.item_title ||
                        oldNode.attrs.optional !== node.attrs.optional ||
                        oldNode.attrs.help !== node.attrs.help
                    ) {
                        allowed = false
                    } else if (
                        node.type.name === 'table_part' &&
                        node.attrs.locking === 'header' &&
                        !node.firstChild.firstChild.eq(oldNode.firstChild.firstChild)
                    ) {
                        allowed = false
                    }
                    return true
                }
                if (pos < range.from) {
                    return true
                }
                if (node === tr.doc.firstChild) {
                    // block some settings changes
                    const oldNode = state.doc.firstChild
                    if (
                        oldNode.attrs.footnote_marks !== node.attrs.footnote_marks ||
                        oldNode.attrs.footnote_elements !== node.attrs.footnote_elements ||
                        oldNode.attrs.languages !== node.attrs.languages ||
                        oldNode.attrs.papersizes !== node.attrs.papersizes ||
                        oldNode.attrs.template !== node.attrs.template ||
                        !node.attrs.papersizes.includes(node.attrs.papersize) ||
                        !node.attrs.languages.includes(node.attrs.language)
                    ) {
                        allowed = false
                        return false
                    } else {
                        allowed = true
                        return true
                    }
                }
                if (
                    allowedElements &&
                    !allowedElements.includes(node.type.name)
                ) {
                    allowed = false
                } else if (allowedMarks) {
                    node.marks.forEach(mark => {
                        if (!allowedMarks.includes(mark.type.name)) {
                            allowed = false
                        }
                    })
                }

            }))

            return allowed
        }
    })
}
<|endoftext|>


<commit_before>define(function(require) {

    'use strict';

    var _    = require('underscore');
    var PIXI = require('pixi');

    var PixiSceneView      = require('common/pixi/view/scene');
    var ModelViewTransform = require('common/math/model-view-transform');
    var Rectangle          = require('common/math/rectangle');
    var Vector2            = require('common/math/vector2');

    var InfraredFilter = require('models/filter/infrared');

    var PhotonView = require('views/photon');
    var CloudView  = require('views/cloud');

    var Assets = require('assets');

    // Constants
    var Constants = require('constants');

    // CSS
    require('less!styles/scene');

    /**
     *
     */
    var BaseGreenhouseSceneView = PixiSceneView.extend({

        visiblePhotonProportion: 0.1,

        initialize: function(options) {
            PixiSceneView.prototype.initialize.apply(this, arguments);

            this.listenTo(this.simulation.photons, 'reset',          this.photonsReset);
            this.listenTo(this.simulation.photons, 'add',            this.photonAdded);
            this.listenTo(this.simulation.photons, 'remove destroy', this.photonRemoved);
        },

        renderContent: function() {

        },

        initGraphics: function() {
            PixiSceneView.prototype.initGraphics.apply(this, arguments);

            this.backgroundLayer = new PIXI.DisplayObjectContainer();
            this.foregroundLayer = new PIXI.DisplayObjectContainer();

            this.stage.addChild(this.backgroundLayer);
            this.stage.addChild(this.foregroundLayer);

            this.initMVT();
            this.initBackground();
            this.initPhotons();

            this.initialized = true;
        },

        initMVT: function() {
            // Map the simulation bounds...
            var bounds = this.simulation.bounds;

            // ...to the usable screen space that we have
            var controlsWidth = 210;
            var usableScreenSpace = new Rectangle(0, 0, this.width - controlsWidth, this.height);

            if ($(window).height() <= 500) {
                usableScreenSpace.x += controlsWidth;
                usableScreenSpace.w -= controlsWidth;
            }

            var boundsRatio = bounds.w / bounds.h;
            var screenRatio = usableScreenSpace.w / usableScreenSpace.h;

            var scale = (screenRatio > boundsRatio) ? usableScreenSpace.h / bounds.h : usableScreenSpace.w / bounds.w;

            this.viewOriginX = Math.round(usableScreenSpace.x + usableScreenSpace.w / 2);
            this.viewOriginY = Math.round(usableScreenSpace.y + usableScreenSpace.h);

            this.mvt = ModelViewTransform.createSinglePointScaleInvertedYMapping(
                new Vector2(0, 0),
                new Vector2(this.viewOriginX, this.viewOriginY),
                scale
            );
        },

        initBackground: function() {},

        createScene: function(image) {
            var scene = Assets.createSprite(image);
            scene.anchor.y = 1;
            scene.y = this.height;
            scene.visible = false;
            this.setSceneScale(scene);

            return scene;
        },

        setSceneScale: function(scene) {
            var targetSceneWidth = this.width; // In pixels
            scene.scale.x = targetSceneWidth / scene.width;
            scene.scale.y = targetSceneWidth / scene.width;
        },

        initPhotons: function() {
            this.photonViews = [];

            this.sunlightPhotons = new PIXI.SpriteBatch();
            this.infraredPhotons = new PIXI.SpriteBatch();

            // Sunlight goes on top because it goes over the glass
            this.backgroundLayer.addChild(this.infraredPhotons);
            this.backgroundLayer.addChild(this.sunlightPhotons);

            this.irFilter = new InfraredFilter();

            this.photonsReset(this.simulation.photons);
        },

        _update: function(time, deltaTime, paused, timeScale) {

        },

        photonAdded: function(photon, photons) {
            this.createAndAddPhotonView(photon);
        },

        photonRemoved: function(photon, photons) {
            for (var i = this.photonViews.length - 1; i >= 0; i--) {
                if (this.photonViews[i].model === photon) {
                    this.photonViews[i].removeFrom(this.photonViews[i].displayObject.parent);
                    this.photonViews.splice(i, 1);
                    break;
                }
            }
        },

        photonsReset: function(photons) {
            // Remove old photon views
            for (var i = this.photonViews.length - 1; i >= 0; i--) {
                this.photonViews[i].removeFrom(this.photonViews[i].displayObject.parent);
                this.photonViews.splice(i, 1);
            }

            // Add new photon views
            photons.each(function(photon) {
                this.createAndAddPhotonView(photon);
            }, this);
        },

        createAndAddPhotonView: function(photon) {
            var photonView = new PhotonView({
                model: photon,
                mvt: this.mvt,
                visibleProportion: this.visiblePhotonProportion
            });

            // Add them to the right layer based on wavelength
            if (this.irFilter.absorbs(photon.get('wavelength')))
                this.infraredPhotons.addChild(photonView.displayObject);
            else
                this.sunlightPhotons.addChild(photonView.displayObject);

            this.photonViews.push(photonView);
        },

        setVisiblePhotonProportion: function(visiblePhotonProportion) {
            this.visiblePhotonProportion = visiblePhotonProportion;
            for (var i = 0; i < this.photonViews.length; i++)
                this.photonViews[i].updateVisibility(visiblePhotonProportion);
        },

        showAllPhotons: function() {
            this.setVisiblePhotonProportion(1);
        },

        showFewerPhotons: function() {
            this.setVisiblePhotonProportion(0.1);
        }

    });

    return BaseGreenhouseSceneView;
});
<commit_msg>Calculating the usable screen space differently to make the bounds of the glass panes nicer.<commit_after>define(function(require) {

    'use strict';

    var _    = require('underscore');
    var PIXI = require('pixi');

    var PixiSceneView      = require('common/pixi/view/scene');
    var ModelViewTransform = require('common/math/model-view-transform');
    var Rectangle          = require('common/math/rectangle');
    var Vector2            = require('common/math/vector2');

    var InfraredFilter = require('models/filter/infrared');

    var PhotonView = require('views/photon');
    var CloudView  = require('views/cloud');

    var Assets = require('assets');

    // Constants
    var Constants = require('constants');

    // CSS
    require('less!styles/scene');

    /**
     *
     */
    var BaseGreenhouseSceneView = PixiSceneView.extend({

        visiblePhotonProportion: 0.1,

        initialize: function(options) {
            PixiSceneView.prototype.initialize.apply(this, arguments);

            this.listenTo(this.simulation.photons, 'reset',          this.photonsReset);
            this.listenTo(this.simulation.photons, 'add',            this.photonAdded);
            this.listenTo(this.simulation.photons, 'remove destroy', this.photonRemoved);
        },

        renderContent: function() {

        },

        initGraphics: function() {
            PixiSceneView.prototype.initGraphics.apply(this, arguments);

            this.backgroundLayer = new PIXI.DisplayObjectContainer();
            this.foregroundLayer = new PIXI.DisplayObjectContainer();

            this.stage.addChild(this.backgroundLayer);
            this.stage.addChild(this.foregroundLayer);

            this.initMVT();
            this.initBackground();
            this.initPhotons();

            this.initialized = true;
        },

        initMVT: function() {
            // Map the simulation bounds...
            var bounds = this.simulation.bounds;

            // ...to the usable screen space that we have
            var controlsWidth = 180;
            var margin = 20;
            var leftMargin = ($(window).height() <= 500) ? margin + controlsWidth + margin : margin;
            var rightMargin = margin + controlsWidth + margin;
            var usableScreenSpace = new Rectangle(leftMargin, 0, this.width - leftMargin - rightMargin, this.height);

            var boundsRatio = bounds.w / bounds.h;
            var screenRatio = usableScreenSpace.w / usableScreenSpace.h;

            var scale = (screenRatio > boundsRatio) ? usableScreenSpace.h / bounds.h : usableScreenSpace.w / bounds.w;

            this.viewOriginX = Math.round(usableScreenSpace.x + usableScreenSpace.w / 2);
            this.viewOriginY = Math.round(usableScreenSpace.y + usableScreenSpace.h);

            this.mvt = ModelViewTransform.createSinglePointScaleInvertedYMapping(
                new Vector2(0, 0),
                new Vector2(this.viewOriginX, this.viewOriginY),
                scale
            );
        },

        initBackground: function() {},

        createScene: function(image) {
            var scene = Assets.createSprite(image);
            scene.anchor.y = 1;
            scene.y = this.height;
            scene.visible = false;
            this.setSceneScale(scene);

            return scene;
        },

        setSceneScale: function(scene) {
            var targetSceneWidth = this.width; // In pixels
            scene.scale.x = targetSceneWidth / scene.width;
            scene.scale.y = targetSceneWidth / scene.width;
        },

        initPhotons: function() {
            this.photonViews = [];

            this.sunlightPhotons = new PIXI.SpriteBatch();
            this.infraredPhotons = new PIXI.SpriteBatch();

            // Sunlight goes on top because it goes over the glass
            this.backgroundLayer.addChild(this.infraredPhotons);
            this.backgroundLayer.addChild(this.sunlightPhotons);

            this.irFilter = new InfraredFilter();

            this.photonsReset(this.simulation.photons);
        },

        _update: function(time, deltaTime, paused, timeScale) {

        },

        photonAdded: function(photon, photons) {
            this.createAndAddPhotonView(photon);
        },

        photonRemoved: function(photon, photons) {
            for (var i = this.photonViews.length - 1; i >= 0; i--) {
                if (this.photonViews[i].model === photon) {
                    this.photonViews[i].removeFrom(this.photonViews[i].displayObject.parent);
                    this.photonViews.splice(i, 1);
                    break;
                }
            }
        },

        photonsReset: function(photons) {
            // Remove old photon views
            for (var i = this.photonViews.length - 1; i >= 0; i--) {
                this.photonViews[i].removeFrom(this.photonViews[i].displayObject.parent);
                this.photonViews.splice(i, 1);
            }

            // Add new photon views
            photons.each(function(photon) {
                this.createAndAddPhotonView(photon);
            }, this);
        },

        createAndAddPhotonView: function(photon) {
            var photonView = new PhotonView({
                model: photon,
                mvt: this.mvt,
                visibleProportion: this.visiblePhotonProportion
            });

            // Add them to the right layer based on wavelength
            if (this.irFilter.absorbs(photon.get('wavelength')))
                this.infraredPhotons.addChild(photonView.displayObject);
            else
                this.sunlightPhotons.addChild(photonView.displayObject);

            this.photonViews.push(photonView);
        },

        setVisiblePhotonProportion: function(visiblePhotonProportion) {
            this.visiblePhotonProportion = visiblePhotonProportion;
            for (var i = 0; i < this.photonViews.length; i++)
                this.photonViews[i].updateVisibility(visiblePhotonProportion);
        },

        showAllPhotons: function() {
            this.setVisiblePhotonProportion(1);
        },

        showFewerPhotons: function() {
            this.setVisiblePhotonProportion(0.1);
        }

    });

    return BaseGreenhouseSceneView;
});
<|endoftext|>


<commit_before>(function($) {

	/**
	 * FlipClock Norwegian-Bokmål Language Pack
	 *
	 * This class will used to translate tokens into the Norwegian language.
	 *
	 */

	FlipClock.Lang.Norwegian-BM = {

		'years'   : 'År',
		'months'  : 'Måneder',
		'days'    : 'Dager',
		'hours'   : 'Timer',
		'minutes' : 'Minutter',
		'seconds' : 'Sekunder'

	};

	/* Create various aliases for convenience */

	FlipClock.Lang['no']      = FlipClock.Lang.Norwegian-BM;
	FlipClock.Lang['nb']      = FlipClock.Lang.Norwegian-BM;
	FlipClock.Lang['no-nb']   = FlipClock.Lang.Norwegian-BM;
	FlipClock.Lang['norwegian'] = FlipClock.Lang.Norwegian-BM;

}(jQuery));
<commit_msg>Updated Norwegian language pack<commit_after>(function($) {

	/**
	 * FlipClock Norwegian-Bokmål Language Pack
	 *
	 * This class will used to translate tokens into the Norwegian language.
	 *
	 */

	FlipClock.Lang.Norwegian = {

		'years'   : 'År',
		'months'  : 'Måneder',
		'days'    : 'Dager',
		'hours'   : 'Timer',
		'minutes' : 'Minutter',
		'seconds' : 'Sekunder'

	};

	/* Create various aliases for convenience */

	FlipClock.Lang['no']      = FlipClock.Lang.Norwegian;
	FlipClock.Lang['nb']      = FlipClock.Lang.Norwegian;
	FlipClock.Lang['no-nb']   = FlipClock.Lang.Norwegian;
	FlipClock.Lang['norwegian'] = FlipClock.Lang.Norwegian;

}(jQuery));
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.stack',
  name: 'StackView',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.stack.Stack'
  ],

  exports: [ 'data as stack' ],

  properties: [
    {
      name: 'data',
      factory: function() { return this.Stack.create(); }
    },
    {
      class: 'Boolean',
      name: 'showActions',
      value: true
    }
  ],

  methods: [
    function init() {
      this.setNodeName('div');

      if ( this.showActions )
        this.add(this.Stack.BACK, this.Stack.FORWARD);

      this.add(this.slot(function(s) {
        return foam.u2.ViewSpec.createView(s, null, this, this.__subSubContext__);
      }, this.data$.dot('top')));
    }
  ]
});
<commit_msg>Switch to initE in StackView.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.u2.stack',
  name: 'StackView',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.stack.Stack'
  ],

  exports: [ 'data as stack' ],

  properties: [
    {
      name: 'data',
      factory: function() { return this.Stack.create(); }
    },
    {
      class: 'Boolean',
      name: 'showActions',
      value: true
    }
  ],

  methods: [
    function initE() {
      this.setNodeName('div');

      if ( this.showActions )
        this.add(this.Stack.BACK, this.Stack.FORWARD);

      this.add(this.slot(function(s) {
        return foam.u2.ViewSpec.createView(s, null, this, this.__subSubContext__);
      }, this.data$.dot('top')));
    }
  ]
});
<|endoftext|>


<commit_before>define([
        '../../config',
        '../../lib/mustache'
        ],
        function(config, Mustache){

    var Cong_Fields = Backbone.View.extend({
        initialize:function(){
             // List field names
            var field_names = [
                      'name',
                      'meeting_address1',
                      'meeting_address2',
                      'meeting_city',
                      'meeting_state',
                      'meeting_zip',
                      'meeting_country',
                      'mailing_address1',
                      'mailing_address2',
                      'mailing_city',
                      'mailing_state',
                      'mailing_zip',
                      'mailing_country',
                      'phone',
                      'fax',
                      'email',
                      'website',
                      'service_info',
                      'date_founded'
                    ]
            // Format field names
            fields = []
            for (var i=0; i < field_names.length; i++){
                fields.push({
                  pretty_name:config.capitalize(field_names[i].replace('_', ' ')),
                  db_name:field_names[i]
                })
            }
        },
        render: function(){
//          var id = "#confirm_cong_id_template"
//          $(id).hide()
//          config.render_to_id(this, id)
//          $(id).show(3000)
            // Render Mustache template
            var tmpl = $('#fields_template').html();
            var fields_html = Mustache.render(tmpl, {fields:fields})
            $('#fields_table_container').append(fields_html);
        },
        events: {
            "focus #fields_table_mustache input[type=text]": "display_button",
        },
        display_button:function(event) {
    		// Record which field's text box was clicked in a global variable
    		selected_field = $(event.target).attr('id');
    		// Show this field's "No, this isn't right" button, and hide all others
    		$('#fields_table_mustache button').hide();
    		$('#' + selected_field + '_button').show();
    		// Create global directory.fields object if it doesn't already exist
    		if (typeof directory.fields === 'undefined') {
    			directory.fields = {};
    		}
    		// TODO:  This doesn't actually work yet, for some reason
    		// If this field's settings have already been stored in directory.fields,
    		//		load it in the textarea
    		if (directory.fields[selected_field]!=undefined){
    			$('#details_regex').val(directory.fields[selected_field].regex);
    		}
    		// Listen for and handle a selection event
    		$('#cong_details_fields_selector').mouseup(create_regular_expression());

        }
    });
    return Cong_Fields

});<commit_msg>Added TODO comment<commit_after>define([
        '../../config',
        '../../lib/mustache'
        ],
        function(config, Mustache){

    var Cong_Fields = Backbone.View.extend({
        initialize:function(){
             // List field names
            var field_names = [
                      'name',
                      'meeting_address1',
                      'meeting_address2',
                      'meeting_city',
                      'meeting_state',
                      'meeting_zip',
                      'meeting_country',
                      'mailing_address1',
                      'mailing_address2',
                      'mailing_city',
                      'mailing_state',
                      'mailing_zip',
                      'mailing_country',
                      'phone',
                      'fax',
                      'email',
                      'website',
                      'service_info',
                      'date_founded'
                    ]
            // Format field names
            fields = []
            for (var i=0; i < field_names.length; i++){
                fields.push({
                  pretty_name:config.capitalize(field_names[i].replace('_', ' ')),
                  db_name:field_names[i]
                })
            }
        },
        render: function(){
//          var id = "#confirm_cong_id_template"
//          $(id).hide()
//          config.render_to_id(this, id)
//          $(id).show(3000)
            // Render Mustache template
            var tmpl = $('#fields_template').html();
            var fields_html = Mustache.render(tmpl, {fields:fields})
            $('#fields_table_container').append(fields_html);
        },
        events: {
            "focus #fields_table_mustache input[type=text]": "display_button",
        },
        display_button:function(event) {
    		// Record which field's text box was clicked in a global variable
    		selected_field = $(event.target).attr('id');
    		// Show this field's "No, this isn't right" button, and hide all others
    		$('#fields_table_mustache button').hide();
    		$('#' + selected_field + '_button').show();
    		// Create global directory.fields object if it doesn't already exist
            // TODO: directory itself doesn't exist yet, so this throws an error
    		if (typeof directory.fields === 'undefined') {
    			directory.fields = {};
    		}
    		// TODO:  This doesn't actually work yet, for some reason
    		// If this field's settings have already been stored in directory.fields,
    		//		load it in the textarea
    		if (directory.fields[selected_field]!=undefined){
    			$('#details_regex').val(directory.fields[selected_field].regex);
    		}
    		// Listen for and handle a selection event
    		$('#cong_details_fields_selector').mouseup(create_regular_expression());

        }
    });
    return Cong_Fields

});<|endoftext|>


<commit_before>/**
 * Router definition.
 */
angular.module('app.contacts').config(contactConfig);

contactConfig.$inject = ['$stateProvider'];
function contactConfig($stateProvider) {
    $stateProvider.state('base.contacts.create', {
        url: '/create',
        views: {
            '@': {
                templateUrl: 'contacts/controllers/form_outer.html',
                controller: ContactCreateUpdateController,
                controllerAs: 'vm'
            }
        },
        ncyBreadcrumb: {
            label: 'Create'
        }
    });

    $stateProvider.state('base.contacts.detail.edit', {
        url: '/edit',
        views: {
            '@': {
                templateUrl: 'contacts/controllers/form_outer.html',
                controller: ContactCreateUpdateController,
                controllerAs: 'vm'
            }
        },
        ncyBreadcrumb: {
            label: 'Edit'
        }
    });

    $stateProvider.state('base.contacts.create.fromAccount', {
        url: '/account/{accountId:[0-9]{1,}}',
        views: {
            '@': {
                templateUrl: 'contacts/controllers/form_outer.html',
                controller: ContactCreateUpdateController,
                controllerAs: 'vm'
            }
        },
        ncyBreadcrumb: {
            skip: true
        }
    });
}

/**
 * Controller to create a new contact.
 */
angular.module('app.contacts').controller('ContactCreateUpdateController', ContactCreateUpdateController);

ContactCreateUpdateController.$inject = ['$scope', '$state', '$stateParams', 'Account', 'Contact', 'HLFields', 'HLForms'];
function ContactCreateUpdateController($scope, $state, $stateParams, Account, Contact, HLFields, HLForms) {
    var vm = this;
    vm.contact = {};
    vm.tags = [];
    vm.errors = {
        name: []
    };
    vm.accounts = [];

    vm.saveContact = saveContact;
    vm.addRelatedField = addRelatedField;
    vm.removeRelatedField = removeRelatedField;
    vm.refreshAccounts = refreshAccounts;

    activate();

    ////

    function activate() {
        $scope.conf.pageTitleSmall = 'change is natural';

        _getContact();
    }

    function _getContact() {
        // Fetch the contact or create empty contact
        if ($stateParams.id) {
            $scope.conf.pageTitleBig = 'Edit contact';
            Contact.get({id: $stateParams.id}).$promise.then(function (contact) {
                vm.contact = contact;

                if (vm.contact.hasOwnProperty('tags') && vm.contact.tags.length) {
                    var tags = [];
                    angular.forEach(vm.contact.tags, function (tag) {
                        tags.push(tag.name);
                    });

                    vm.contact.tags = tags;
                }

                if (vm.contact.hasOwnProperty('social_media') && vm.contact.social_media.length) {
                    angular.forEach(vm.contact.social_media, function (profile) {
                        vm.contact[profile.name] = profile.username;
                    });
                }

                $scope.conf.pageTitleBig = vm.contact.name;
            });
        } else {
            $scope.conf.pageTitleBig = 'New contact';
            vm.contact = Contact.create();

            if ($stateParams.accountId) {
                var account = Account.get({id: $stateParams.accountId});
                vm.contact.accounts.push(account);
            }
        }
    }

    function addRelatedField(field) {
        HLFields.addRelatedField(vm.contact, field);
    }

    function removeRelatedField(field, index, remove) {
        HLFields.removeRelatedField(vm.contact, field, index, remove);
    }

    function saveContact(form) {
        if (vm.contact.tags && vm.contact.tags.length) {
            var tags = [];

            angular.forEach(vm.contact.tags, function (tag) {
                if (tag) {
                    tags.push({name: (tag.name) ? tag.name : tag});
                }
            });

            vm.contact.tags = tags;
        }

        if (vm.contact.accounts && vm.contact.accounts.length) {
            var accounts = [];

            angular.forEach(vm.contact.accounts, function (account) {
                if (account) {
                    accounts.push({id: account.id});
                }
            });
        }

        // Clear all errors of the form (in case of new errors)
        angular.forEach(form, function(value, key) {
            if (typeof value === 'object' && value.hasOwnProperty('$modelValue')) {
                form[key].$error = {};
                form[key].$setValidity(key, true);
            }
        });

        vm.contact.social_media = [];

        if (vm.contact.twitter) {
            vm.contact.social_media.push({
                name: 'twitter',
                username: vm.contact.twitter
            })
        }

        if (vm.contact.linkedin) {
            vm.contact.social_media.push({
                name: 'linkedin',
                username: vm.contact.linkedin
            })
        }

        vm.contact = HLFields.cleanRelatedFields(vm.contact);

        if (vm.contact.id) {
            // If there's an ID set it means we're dealing with an existing contact, so update it
            vm.contact.$update(function () {
                toastr.success('I\'ve updated the contact for you!', 'Done');
                $state.go('base.contacts.detail', {id: vm.contact.id}, {reload: true});
            }, function (response) {
                _handleBadResponse(response, form);
            })
        }
        else {
            vm.contact.$save(function () {
                toastr.success('I\'ve saved the contact for you!', 'Yay');
                $state.go('base.contacts.detail', {id: vm.contact.id});
            }, function (response) {
                _handleBadResponse(response, form);
            });
        }
    }

    function refreshAccounts(query) {
        if (query.length >= 2) {
            vm.accounts = Account.search({filterquery: 'name:(' + query + ')', size: 60});
        }
    }

    function _handleBadResponse(response, form) {
        HLForms.setErrors(form, response.data);

        toastr.error('Uh oh, there seems to be a problem', 'Oops!');
    }
}
<commit_msg>Exclude accounts already selected in works at field<commit_after>/**
 * Router definition.
 */
angular.module('app.contacts').config(contactConfig);

contactConfig.$inject = ['$stateProvider'];
function contactConfig($stateProvider) {
    $stateProvider.state('base.contacts.create', {
        url: '/create',
        views: {
            '@': {
                templateUrl: 'contacts/controllers/form_outer.html',
                controller: ContactCreateUpdateController,
                controllerAs: 'vm'
            }
        },
        ncyBreadcrumb: {
            label: 'Create'
        }
    });

    $stateProvider.state('base.contacts.detail.edit', {
        url: '/edit',
        views: {
            '@': {
                templateUrl: 'contacts/controllers/form_outer.html',
                controller: ContactCreateUpdateController,
                controllerAs: 'vm'
            }
        },
        ncyBreadcrumb: {
            label: 'Edit'
        }
    });

    $stateProvider.state('base.contacts.create.fromAccount', {
        url: '/account/{accountId:[0-9]{1,}}',
        views: {
            '@': {
                templateUrl: 'contacts/controllers/form_outer.html',
                controller: ContactCreateUpdateController,
                controllerAs: 'vm'
            }
        },
        ncyBreadcrumb: {
            skip: true
        }
    });
}

/**
 * Controller to create a new contact.
 */
angular.module('app.contacts').controller('ContactCreateUpdateController', ContactCreateUpdateController);

ContactCreateUpdateController.$inject = ['$scope', '$state', '$stateParams', 'Account', 'Contact', 'HLFields', 'HLForms'];
function ContactCreateUpdateController($scope, $state, $stateParams, Account, Contact, HLFields, HLForms) {
    var vm = this;
    vm.contact = {};
    vm.tags = [];
    vm.errors = {
        name: []
    };
    vm.accounts = [];

    vm.saveContact = saveContact;
    vm.addRelatedField = addRelatedField;
    vm.removeRelatedField = removeRelatedField;
    vm.refreshAccounts = refreshAccounts;

    activate();

    ////

    function activate() {
        $scope.conf.pageTitleSmall = 'change is natural';

        _getContact();
    }

    function _getContact() {
        // Fetch the contact or create empty contact
        if ($stateParams.id) {
            $scope.conf.pageTitleBig = 'Edit contact';
            Contact.get({id: $stateParams.id}).$promise.then(function (contact) {
                vm.contact = contact;

                if (vm.contact.hasOwnProperty('tags') && vm.contact.tags.length) {
                    var tags = [];
                    angular.forEach(vm.contact.tags, function (tag) {
                        tags.push(tag.name);
                    });

                    vm.contact.tags = tags;
                }

                if (vm.contact.hasOwnProperty('social_media') && vm.contact.social_media.length) {
                    angular.forEach(vm.contact.social_media, function (profile) {
                        vm.contact[profile.name] = profile.username;
                    });
                }

                $scope.conf.pageTitleBig = vm.contact.name;
            });
        } else {
            $scope.conf.pageTitleBig = 'New contact';
            vm.contact = Contact.create();

            if ($stateParams.accountId) {
                var account = Account.get({id: $stateParams.accountId});
                vm.contact.accounts.push(account);
            }
        }
    }

    function addRelatedField(field) {
        HLFields.addRelatedField(vm.contact, field);
    }

    function removeRelatedField(field, index, remove) {
        HLFields.removeRelatedField(vm.contact, field, index, remove);
    }

    function saveContact(form) {
        if (vm.contact.tags && vm.contact.tags.length) {
            var tags = [];

            angular.forEach(vm.contact.tags, function (tag) {
                if (tag) {
                    tags.push({name: (tag.name) ? tag.name : tag});
                }
            });

            vm.contact.tags = tags;
        }

        if (vm.contact.accounts && vm.contact.accounts.length) {
            var accounts = [];

            angular.forEach(vm.contact.accounts, function (account) {
                if (account) {
                    accounts.push({id: account.id});
                }
            });
        }

        // Clear all errors of the form (in case of new errors)
        angular.forEach(form, function(value, key) {
            if (typeof value === 'object' && value.hasOwnProperty('$modelValue')) {
                form[key].$error = {};
                form[key].$setValidity(key, true);
            }
        });

        vm.contact.social_media = [];

        if (vm.contact.twitter) {
            vm.contact.social_media.push({
                name: 'twitter',
                username: vm.contact.twitter
            })
        }

        if (vm.contact.linkedin) {
            vm.contact.social_media.push({
                name: 'linkedin',
                username: vm.contact.linkedin
            })
        }

        vm.contact = HLFields.cleanRelatedFields(vm.contact);

        if (vm.contact.id) {
            // If there's an ID set it means we're dealing with an existing contact, so update it
            vm.contact.$update(function () {
                toastr.success('I\'ve updated the contact for you!', 'Done');
                $state.go('base.contacts.detail', {id: vm.contact.id}, {reload: true});
            }, function (response) {
                _handleBadResponse(response, form);
            })
        }
        else {
            vm.contact.$save(function () {
                toastr.success('I\'ve saved the contact for you!', 'Yay');
                $state.go('base.contacts.detail', {id: vm.contact.id});
            }, function (response) {
                _handleBadResponse(response, form);
            });
        }
    }

    function refreshAccounts(query) {
        if (query.length >= 2) {
            var exclude = '';

            // Exclude accounts already selected
            angular.forEach(vm.contact.accounts, function (account) {
                exclude += ' AND NOT id:' + account.id;
            });

            vm.accounts = Account.search({filterquery: 'name:(' + query + ')' + exclude, size: 60});
        }
    }

    function _handleBadResponse(response, form) {
        HLForms.setErrors(form, response.data);

        toastr.error('Uh oh, there seems to be a problem', 'Oops!');
    }
}
<|endoftext|>