<commit_before>jQuery(document).ready(function($) {
    var jcrop_api;

    $.ajaxSetup({
        type: "POST",
        url: _hh_ajax_fe_profile.ajaxurl
    });

    if ( $('#profile-editor-container').length ) hh_profile_edit_ajax_load_template();

    $(document).on('submit','.hh-update-profile',function(e) {
        e.preventDefault();

        var formfield = $(this).attr('data-meta_key');
        var $formfield = $('#main-'+formfield);
        var meta_key = $formfield.attr('data-meta_key');  console.log('meta_key: '+meta_key);
        var nonce = $formfield.attr('data-nonce');  console.log('nonce: '+nonce);
        var meta_value = $('#input-'+meta_key).val();  console.log('meta_value: '+meta_value);

        $.ajax({
            dataType : "json",
            data : {action: "hh_update_user_profile", meta_key : meta_key, meta_value : meta_value, nonce: nonce},
            beforeSend: function() {
                edit_stop(meta_key);
                edit_alert_show(meta_key,'info','Submitting Request...',true);
                $('.edit-field').addClass('disabled');
            },
            complete: function() {
                edit_stop(meta_key);
                $('#message-'+meta_key).hide();
            },
            success: function(response) {
                var $data = $('#data-'+meta_key);
                $data.html(response.new_value);
                $('Updated').insertAfter('#data-'+meta_key);
                $('.fadeOut').fadeOut(1600,function(){
                    $(this).remove();
                    $('.edit-field').removeClass('disabled');
                });
            },
            error: function () {
                var $data = $('#data-'+meta_key);
                $('Failed!!').insertAfter('#data-'+meta_key);
                $('.fadeOut').fadeOut(2600,function(){
                    $(this).remove();
                    $('.edit-field').removeClass('disabled');
                });
            }
        });
    });

    $(document).on('click','.edit-field', function() {
        if ( $(this).hasClass('disabled') ) return;
        edit_start($(this).attr('data-meta_key'));
    });

    $(document).on('click','.pr-cancel', function() {
        edit_stop($(this).attr('data-meta_key'));
    });

    function edit_start(meta_key) {
        $('#current_meta_key').val(meta_key);
        $('#'+meta_key).show();
        $('#main-'+meta_key).addClass('edit-highlight');
        $('#swap-'+meta_key).hide();
        $('#pad-'+meta_key).addClass('field-highlight').css('padding','0');
        $('#controls-'+meta_key).show().css('height','auto');
        $('#input-'+meta_key).focus();
    }
    function edit_stop(meta_key) {
        $('#'+meta_key).removeAttr('style');
        $('#input-'+meta_key).val($('#data-'+meta_key).text());
        $('#main-'+meta_key).removeClass('edit-highlight').removeAttr('style');
        $('#pad-'+meta_key).removeClass('field-highlight').removeAttr('style');
        $('#swap-'+meta_key).removeAttr('style');
        $('#controls-'+meta_key).removeAttr('style');
    }

    function edit_alert_show(meta_key,type,message,show_process) {
        $('#main-'+meta_key).addClass('disabled');
        $('#pad-'+meta_key).hide();
        var processing_img = $('#hh_update_profile').attr('data-processing-uri');
        var msg  = '
';
        msg  += '
'+message+'
';
        if (show_process) {
            msg += '';
        }
        msg += '
';
        $('#message-'+meta_key).html(msg).show();
    }

    /**
     * When you click on your profile picture in form.
     */
    $(document).on('click','#hh-change-profile-photo',function(e) {
        e.preventDefault();
        $('#fileUpload-container').show();
        $('.edit-field').addClass('disabled');
    });

    /**
     * When you click you click on the X button to close the container
     */
    $(document).on('click','.close-fileUpload-container',function() {
        location.reload();
        /*
        var previewFields = $('.fileUpload-preview');
        var selectFields = $('.fileUpload-select');
        var errorFields = $('.fileUpload-error');
        var cropFields = $('.fileUpload-crop');
        selectFields.hide();
        cropFields.hide();
        $('#fileUpload-canvas').removeAttr('style');
        previewFields.hide().removeAttr('style');
        errorFields.hide();
        selectFields.show();
        if (jcrop_api) {
            jcrop_api.destroy();
        }
        $('#fileUpload-container').hide();
        $('.edit-field').removeClass('disabled');
        */
    });

    /**
     *  When the input id fileUpload-file has changed.
     */
    $(document).on('change','#fileUpload-file', function() {

        var file = this.files[0];
        var valid_exts = ['jpeg', 'jpg', 'png', 'gif']; // valid extensions
        var ext = file.name.split('.').pop().toLowerCase();
        if (valid_exts.indexOf(ext) > -1) {
            if (file.size < 1048576) {
                /* html FileRender Api */
                var oFReader = new FileReader();
                oFReader.readAsDataURL(document.getElementById("fileUpload-file").files[0]);
                oFReader.onload = function (oFREvent) {
                    $('.fileUpload-select').hide();
                    $('.fileUpload-preview').show();
                    $editImage = $('#fileUpload-preview');
                    $editImage.removeAttr('style');
                    $editImage.css('visibility', 'visible');
                    $editImage.attr('src', oFREvent.target.result).fadeIn();
                    $canvas = $('#fileUpload-canvas');
                    $editImage.Jcrop({
                        setSelect: [100,100,400,400],
                        minSize: [150,150],
                        aspectRatio: 1,
                        boxWidth: $canvas.width()
                    },function() {
                        jcrop_api = this;
                        $canvas.width(jcrop_api.getWidgetSize()[0]);
                        $canvas.height(jcrop_api.getWidgetSize()[1]);
                    });

                }
            } else {
                errorFields.fadeIn();
                $('#fileUpload-errorMessage').html('Too big!
 (Your file must be less than 1MB in size)');
            }
        } else {
            errorFields.fadeIn();
            $('#fileUpload-errorMessage').html('Invalid Filetype!
 (Only jpeg, jpg, png, gif are supported)');
        }
    });

    /**
     * Save Cropped Photo
     */
    $(document).on('submit','#fileUpload-container',function(e) {
        debugger;
        e.preventDefault();
        nonce = $(this).attr('data-nonce');
        $.ajax({
            dataType : "json",
            data : {
                action: "hh_save_profile_pic",
                x1 : jcrop_api.setSelect[0] ,
                y1 : jcrop_api.setSelect[1] ,
                x2 : jcrop_api.setSelect[2] ,
                y2 : jcrop_api.setSelect[3] ,
                nonce: nonce
            },
            beforeSend: function() {
                console.log('beforeSend');
            },
            complete: function(response) {
                console.log(response.responseText);
                console.log('complete');
            },
            success: function(response) {
                console.log(response);
            },
            error: function () {
            }
        });

    });

});

window.hh_profile_edit_ajax_load_template = function () {
    jQuery(document).ready(function($) {
        $.ajax({
            dataType : "html",
            data: { action: "hh_ajax_load_profile_editor" },
            success: function (data) {
                $('#profile-editor-preloader').fadeOut('fast');
                $('#profile-editor-container').fadeIn('slow').html(data);
            }
        });

    });
};

<commit_msg>troubleshooting ajax response<commit_after>jQuery(document).ready(function($) {
    var jcrop_api;

    $.ajaxSetup({
        type: "POST",
        url: _hh_ajax_fe_profile.ajaxurl
    });

    if ( $('#profile-editor-container').length ) hh_profile_edit_ajax_load_template();

    $(document).on('submit','.hh-update-profile',function(e) {
        e.preventDefault();

        var formfield = $(this).attr('data-meta_key');
        var $formfield = $('#main-'+formfield);
        var meta_key = $formfield.attr('data-meta_key');  console.log('meta_key: '+meta_key);
        var nonce = $formfield.attr('data-nonce');  console.log('nonce: '+nonce);
        var meta_value = $('#input-'+meta_key).val();  console.log('meta_value: '+meta_value);

        $.ajax({
            dataType : "json",
            data : {action: "hh_update_user_profile", meta_key : meta_key, meta_value : meta_value, nonce: nonce},
            beforeSend: function() {
                edit_stop(meta_key);
                edit_alert_show(meta_key,'info','Submitting Request...',true);
                $('.edit-field').addClass('disabled');
            },
            complete: function() {
                edit_stop(meta_key);
                $('#message-'+meta_key).hide();
            },
            success: function(response) {
                var $data = $('#data-'+meta_key);
                $data.html(response.new_value);
                $('Updated').insertAfter('#data-'+meta_key);
                $('.fadeOut').fadeOut(1600,function(){
                    $(this).remove();
                    $('.edit-field').removeClass('disabled');
                });
            },
            error: function () {
                var $data = $('#data-'+meta_key);
                $('Failed!!').insertAfter('#data-'+meta_key);
                $('.fadeOut').fadeOut(2600,function(){
                    $(this).remove();
                    $('.edit-field').removeClass('disabled');
                });
            }
        });
    });

    $(document).on('click','.edit-field', function() {
        if ( $(this).hasClass('disabled') ) return;
        edit_start($(this).attr('data-meta_key'));
    });

    $(document).on('click','.pr-cancel', function() {
        edit_stop($(this).attr('data-meta_key'));
    });

    function edit_start(meta_key) {
        $('#current_meta_key').val(meta_key);
        $('#'+meta_key).show();
        $('#main-'+meta_key).addClass('edit-highlight');
        $('#swap-'+meta_key).hide();
        $('#pad-'+meta_key).addClass('field-highlight').css('padding','0');
        $('#controls-'+meta_key).show().css('height','auto');
        $('#input-'+meta_key).focus();
    }
    function edit_stop(meta_key) {
        $('#'+meta_key).removeAttr('style');
        $('#input-'+meta_key).val($('#data-'+meta_key).text());
        $('#main-'+meta_key).removeClass('edit-highlight').removeAttr('style');
        $('#pad-'+meta_key).removeClass('field-highlight').removeAttr('style');
        $('#swap-'+meta_key).removeAttr('style');
        $('#controls-'+meta_key).removeAttr('style');
    }

    function edit_alert_show(meta_key,type,message,show_process) {
        $('#main-'+meta_key).addClass('disabled');
        $('#pad-'+meta_key).hide();
        var processing_img = $('#hh_update_profile').attr('data-processing-uri');
        var msg  = '
';
        msg  += '
'+message+'
';
        if (show_process) {
            msg += '';
        }
        msg += '
';
        $('#message-'+meta_key).html(msg).show();
    }

    /**
     * When you click on your profile picture in form.
     */
    $(document).on('click','#hh-change-profile-photo',function(e) {
        e.preventDefault();
        $('#fileUpload-container').show();
        $('.edit-field').addClass('disabled');
    });

    /**
     * When you click you click on the X button to close the container
     */
    $(document).on('click','.close-fileUpload-container',function() {
        location.reload();
        /*
        var previewFields = $('.fileUpload-preview');
        var selectFields = $('.fileUpload-select');
        var errorFields = $('.fileUpload-error');
        var cropFields = $('.fileUpload-crop');
        selectFields.hide();
        cropFields.hide();
        $('#fileUpload-canvas').removeAttr('style');
        previewFields.hide().removeAttr('style');
        errorFields.hide();
        selectFields.show();
        if (jcrop_api) {
            jcrop_api.destroy();
        }
        $('#fileUpload-container').hide();
        $('.edit-field').removeClass('disabled');
        */
    });

    /**
     *  When the input id fileUpload-file has changed.
     */
    $(document).on('change','#fileUpload-file', function() {

        var file = this.files[0];
        var valid_exts = ['jpeg', 'jpg', 'png', 'gif']; // valid extensions
        var ext = file.name.split('.').pop().toLowerCase();
        if (valid_exts.indexOf(ext) > -1) {
            if (file.size < 1048576) {
                /* html FileRender Api */
                var oFReader = new FileReader();
                oFReader.readAsDataURL(document.getElementById("fileUpload-file").files[0]);
                oFReader.onload = function (oFREvent) {
                    $('.fileUpload-select').hide();
                    $('.fileUpload-preview').show();
                    $editImage = $('#fileUpload-preview');
                    $editImage.removeAttr('style');
                    $editImage.css('visibility', 'visible');
                    $editImage.attr('src', oFREvent.target.result).fadeIn();
                    $canvas = $('#fileUpload-canvas');
                    $editImage.Jcrop({
                        setSelect: [100,100,400,400],
                        minSize: [150,150],
                        aspectRatio: 1,
                        boxWidth: $canvas.width()
                    },function() {
                        jcrop_api = this;
                        $canvas.width(jcrop_api.getWidgetSize()[0]);
                        $canvas.height(jcrop_api.getWidgetSize()[1]);
                    });

                }
            } else {
                errorFields.fadeIn();
                $('#fileUpload-errorMessage').html('Too big!
 (Your file must be less than 1MB in size)');
            }
        } else {
            errorFields.fadeIn();
            $('#fileUpload-errorMessage').html('Invalid Filetype!
 (Only jpeg, jpg, png, gif are supported)');
        }
    });

    /**
     * Save Cropped Photo
     */
    $(document).on('submit','#fileUpload-container',function(e) {
        debugger;
        e.preventDefault();
        nonce = $(this).attr('data-nonce');
        $.ajax({
            dataType : "json",
            data : {
                action: "hh_save_profile_pic",
                x1 : jcrop_api.setSelect[0] ,
                y1 : jcrop_api.setSelect[1] ,
                x2 : jcrop_api.setSelect[2] ,
                y2 : jcrop_api.setSelect[3] ,
                nonce: nonce,
                form: $('fileUpload-container').JSON.stringify(),
            },
            beforeSend: function() {
                console.log('beforeSend');
            },
            complete: function(response) {
                console.log(response.responseText);
                console.log('complete');
            },
            success: function(response) {
                console.log(response);
            },
            error: function () {
            }
        });

    });

});

window.hh_profile_edit_ajax_load_template = function () {
    jQuery(document).ready(function($) {
        $.ajax({
            dataType : "html",
            data: { action: "hh_ajax_load_profile_editor" },
            success: function (data) {
                $('#profile-editor-preloader').fadeOut('fast');
                $('#profile-editor-container').fadeIn('slow').html(data);
            }
        });

    });
};

<|endoftext|>


<commit_before><commit_msg>Added tests for UserService.<commit_after><|endoftext|>


<commit_before>/*********************************************
 *  Copyright (c) 2014 AnsibleWorks, Inc.
 *
 *  Stream.js
 *
 *  Activity stream widget that can be called from anywhere
 *
 */

angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefinition', 'SearchHelper', 'PaginateHelper',
        'RefreshHelper', 'ListGenerator', 'StreamWidget', 'AuthService'])

    .factory('setStreamHeight', [ function() {
    return function() {
        // Try not to overlap footer. Because stream is positioned absolute, the parent
        // doesn't resize correctly when stream is loaded.
        var stream = $('#stream-container');
        var height = stream.height() + 50;
        $('#tab-content-container').css({ "min-height": height });
        }
        }])

    .factory('ShowStream', [ 'setStreamHeight', 'Authorization', function(setStreamHeight, Authorization) {
    return function() {
        // Slide in the Stream widget

        // Make some style/position adjustments adjustments
        var stream = $('#stream-container');
        stream.css({
            position: 'absolute',
            top: 0,
            left: 0,
            width: '100%',
            'min-height': '100%',
            'background-color': '#FFF'
            });

        setStreamHeight();

        // Slide in stream
        stream.show('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });

        }
        }])

    .factory('HideStream', [ 'LoadBreadCrumbs', function(LoadBreadCrumbs) {
    return function() {
        // Remove the stream widget

        var stream = $('#stream-container');
        stream.hide('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });

        // Completely destroy the container so we don't experience random flashes of it later.
        // There was some sort of weirdness with the tab 'show' causing the stream to slide in when
        // a tab was clicked, after the stream had been hidden. Seemed like timing- wait long enough
        // before clicking a tab, and it would not happen.
        setTimeout( function() {
           stream.detach();
           stream.empty();
           stream.unbind();
           $('#tab-content-container').css({ 'min-height': 0 }); //let the parent height go back to normal
           }, 500);

        LoadBreadCrumbs();
        }
        }])

    .factory('StreamBreadCrumbs', ['$rootScope', '$location', function($rootScope, $location) {
    return function() {
        // Load the breadcrumbs array. We have to do things a bit different than Utilities.LoadBreadcrumbs.
        // Rather than botch that all up, we'll do our own thing here.
        $rootScope.breadcrumbs = [];
        var paths = $location.path().split('/');
        paths.splice(0,1);
        var path, title;
        for (var i=0; i < paths.length; i++) {
            if (/^\d+/.test(paths[i])) {
                path='';
                title='';
                for (j=0; j <= i; j++) {
                    path += '/' + paths[j];
                }
                for (j=0; j < $rootScope.crumbCache.length; j++) {
                    if ($rootScope.crumbCache[j].path == path) {
                        title = $rootScope.crumbCache[j].title;
                        break;
                    }
                }
                if (!title) {
                    title = paths[i - 1].substr(0,paths[i - 1].length - 1);
                    title = (title == 'inventorie') ? 'inventory' : title;
                }
            }
            else {
                path='';
                title='';
                if (i > 0) {
                    for (j=0; j <= i; j++) {
                        path += '/' + paths[j];
                    }
                }
                else {
                   path = '/' + paths[i];
                }
                title = paths[i];
            }
            $rootScope.breadcrumbs.push({ path: path, title: title, ngClick: "closeStream('" + path + "')" });
        }
        }
        }])

    .factory('FixUrl', [ function() {
    return function(u) {
        return u.replace(/\/api\/v1\//,'/#/');
        }
        }])

    .factory('BuildUrl', [ function() {
    return function(obj) {
        var url = '/#/';
        switch(obj.base) {
           case 'group':
           case 'host':
               url += 'home/' + obj.base + 's/?name=' + obj.name;
               break;
           case 'inventory':
               url += 'inventories/' + obj.id;
               break;
           default:
               url += obj.base + 's/' + obj.id;
        }
        return url;
        }
        }])

    .factory('BuildDescription', ['FixUrl', 'BuildUrl', function(FixUrl, BuildUrl) {
    return function(activity) {
        var descr = '';
        var descr_nolink;
        descr += activity.operation;
        descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed ';
        descr_nolink = descr;
        var obj1 = activity.object1;
        var obj2 = activity.object2;
        if (activity.summary_fields[obj2] && activity.summary_fields[obj2][0].name) {
            activity.summary_fields[obj2][0]['base'] = obj2;
            descr += obj2 + ' '
                + activity.summary_fields[obj2][0].name + '' + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
            descr_nolink += obj2 + ' ' + activity.summary_fields[obj2][0].name + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
        }
        else if (activity.object2) {
            descr += activity.object2[0] + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
            descr_nolink += activity.object2[0] + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
        }
        if (activity.summary_fields[obj1] && activity.summary_fields[obj1][0].name) {
            activity.summary_fields[obj1][0]['base'] = obj1;
            descr += obj1 + ' '
                + activity.summary_fields[obj1][0].name + '';
            descr_nolink += obj1 + ' ' + activity.summary_fields[obj1][0].name;
        }
        else if (activity.object1) {
            descr += activity.object1;
            descr_nolink += activity.object1;
        }
        activity['description'] = descr;
        activity['description_nolink'] = descr_nolink;
        }
        }])

    .factory('ShowDetail', ['$rootScope', 'Rest', 'Alert', 'GenerateForm', 'ProcessErrors', 'GetBasePath', 'FormatDate',
        'ActivityDetailForm', 'Empty', 'Find',
    function($rootScope, Rest, Alert, GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm, Empty, Find) {
    return function(params) {

        var activity_id = params.activity_id;
        var parent_scope = params.scope;

        var generator = GenerateForm;
        var form = ActivityDetailForm;
        var activity = Find({list: parent_scope.activities, key: 'id', val: activity_id });

        if (activity) {
            // Setup changes field
            activity['changes'] = JSON.stringify(activity['changes'], null, '\t');
            var n = activity['changes'].match(/\n/g);
            var rows = (n) ? n.length : 1;
            rows = (rows < 1) ? 3 : 10;
            form.fields['changes'].rows = 10;

            // Load the form
            var scope = generator.inject(form, { mode: 'edit', modal: true, related: false });
            scope['changes'] = activity['changes'];
            scope['user'] = ( (activity.summary_fields.actor) ? activity.summary_fields.actor.username : 'system' ) +
                ' on ' + FormatDate(new Date(activity['timestamp']));
            scope['operation'] = activity['description_nolink'];

            scope.formModalAction = function() {
                $('#form-modal').modal("hide");
                }

            $('#form-modal').on('show.bs.modal', function (e) {
                $('#form-modal-body').css({
                    width:'auto',  //probably not needed
                    height:'auto', //probably not needed
                    'max-height':'100%'
                    });
                });

            scope.formModalActionLabel = 'OK';
            scope.formModalCancelShow = false;
            scope.formModalInfo = false;
            scope.formModalHeader = "Event " + activity.id;

            if (!scope.$$phase) {
               scope.$digest();
            }
        }

        }
        }])

    .factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
        'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl',
        'ShowDetail', 'StreamBreadCrumbs', 'setStreamHeight', 'Find',
    function($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
        FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail, StreamBreadCrumbs, setStreamHeight,
        Find) {
    return function(params) {

        var list = StreamList;
        var defaultUrl = GetBasePath('activity_stream');
        var view = GenerateList;
        var base = $location.path().replace(/^\//,'').split('/')[0];

        // pass in an inventory name to fix breadcrumb display
        var inventory_name = (params) ? params.inventory_name : null;

        // url will override the attempt to compute an activity_stream query
        var url = (params) ? params.url : null;

        $rootScope.flashMessage = null;

        if (url) {
            defaultUrl = url;
        }
        else {
            if ($location.path() !== '/home') {
                // Restrict what we're looking at based on the path
                var type = (base == 'inventories') ? 'inventory' : base.replace(/s$/,'');
                var paths = $location.path().split('/');
                paths.splice(0,1);
                if (paths.length > 1 && /^\d+/.test(paths[paths.length - 1])) {
                    type = paths[paths.length - 2];
                    type = (type == 'inventories') ? 'inventory' : type.replace(/s$/,'');
                    //defaultUrl += '?object1=' + type + '&object1__id=' +
                    defaultUrl += '?' + type + '__id=' + paths[paths.length - 1];
                }
                else if (paths.length > 1) {
                    type = paths[paths.length - 1];
                    type = (type == 'inventories') ? 'inventory' : type.replace(/s$/,'');
                    defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
                }
                else {
                    defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
                }
            }
        }

        // Add a container for the stream widget
        $('#tab-content-container').append('

');

        StreamBreadCrumbs();

        // Fix inventory name. The way we're doing breadcrumbs doesn't support bind variables.
        if (inventory_name) {
            var itm = Find({ list: $rootScope.breadcrumbs, key: 'title', val: '{{ inventory_name }}' });
            if (itm) {
                itm.title = inventory_name;
            }
        }

        ShowStream();

        // Generate the list
        var scope = view.inject(list, {
            mode: 'edit',
            id: 'stream-content',
            searchSize: 'col-lg-3',
            secondWidget: true,
            activityStream: true
            });

        scope.closeStream = function(inUrl) {
            HideStream();
            if (scope.searchCleanup)
                scope.searchCleanup();
            if (inUrl)
               $location.path(inUrl);
            }

        scope.refreshStream = function() {
            scope.search(list.iterator);
            }

        scope.showDetail = function(id) {
            ShowDetail({ scope: scope, activity_id: id });
            }

        if (scope.removeStreamPostRefresh) {
            scope.removeStreamPostRefresh();
        }
        scope.removeStreamPostRefresh = scope.$on('PostRefresh', function() {
            for (var i=0; i < scope['activities'].length; i++) {
                // Convert event_time date to local time zone
                cDate = new Date(scope['activities'][i].timestamp);
                scope['activities'][i].timestamp = FormatDate(cDate);

                // Display username
                /*scope['activities'][i].user = (scope['activities'][i].summary_fields.user) ? scope['activities'][i].summary_fields.user.username :
                    'system';
                if (scope['activities'][i].user !== 'system') {
                    // turn user into a link when not 'system'
                    scope['activities'][i].user = "" +
                        scope['activities'][i].user + "";
                }*/
                if (scope['activities'][i]['summary_fields']['actor']) {
                    scope['activities'][i]['user'] = "" +
                        scope['activities'][i]['summary_fields']['actor']['username'] + "";
                }
                else {
                    scope['activities'][i]['user'] = 'system';
                }

                // Objects
                var href;
                var deleted = /^\_delete/;
                var obj1 = scope['activities'][i].object1;
                var obj2 = scope['activities'][i].object2;
                if ( obj1 && scope['activities'][i].summary_fields[obj1] && scope['activities'][i].summary_fields[obj1].name) {
                    if ( !deleted.test(scope['activities'][i].summary_fields[obj1].name) ) {
                        href = BuildUrl(scope['activities'][i].summary_fields.object1);
                        scope['activities'][i].objects = "" + scope['activities'][i].summary_fields[obj1].name + "";
                    }
                    else {
                        scope['activities'][i].objects = scope['activities'][i].summary_fields[obj1].name;
                    }
                }
                else if (scope['activities'][i].object1) {
                    scope['activities'][i].objects = scope['activities'][i].object1;
                }
                if (obj2 && scope['activities'][i].summary_fields[obj2] && scope['activities'][i].summary_fields[obj2].name) {
                    if ( !deleted.test(scope['activities'][i].summary_fields.object2.name) ) {
                        href = BuildUrl(scope['activities'][i].summary_fields.object2);
                        scope['activities'][i].objects += ", " + scope['activities'][i].summary_fields[obj2].name + "";
                    }
                    else {
                        scope['activities'][i].objects += "," + scope['activities'][i].summary_fields[obj2].name;
                    }
                }
                else if (scope['activities'][i].object2) {
                    scope['activities'][i].objects += ", " + scope['activities'][i].object2;
                }

                BuildDescription(scope['activities'][i]);

            }
            // Give ng-repeate a chance to show the data before adjusting the page size.
            setTimeout(function() { setStreamHeight(); }, 500);
            });

        // Initialize search and paginate pieces and load data
        SearchInit({ scope: scope, set: list.name, list: list, url: defaultUrl });
        PaginateInit({ scope: scope, list: list, url: defaultUrl });
        scope.search(list.iterator);

        }
        }]);
    <commit_msg>Activity Stream: clicking view detail no longer re-stringifies the changes JSON.<commit_after>/*********************************************
 *  Copyright (c) 2014 AnsibleWorks, Inc.
 *
 *  Stream.js
 *
 *  Activity stream widget that can be called from anywhere
 *
 */

angular.module('StreamWidget', ['RestServices', 'Utilities', 'StreamListDefinition', 'SearchHelper', 'PaginateHelper',
        'RefreshHelper', 'ListGenerator', 'StreamWidget', 'AuthService'])

    .factory('setStreamHeight', [ function() {
    return function() {
        // Try not to overlap footer. Because stream is positioned absolute, the parent
        // doesn't resize correctly when stream is loaded.
        var stream = $('#stream-container');
        var height = stream.height() + 50;
        $('#tab-content-container').css({ "min-height": height });
        }
        }])

    .factory('ShowStream', [ 'setStreamHeight', 'Authorization', function(setStreamHeight, Authorization) {
    return function() {
        // Slide in the Stream widget

        // Make some style/position adjustments adjustments
        var stream = $('#stream-container');
        stream.css({
            position: 'absolute',
            top: 0,
            left: 0,
            width: '100%',
            'min-height': '100%',
            'background-color': '#FFF'
            });

        setStreamHeight();

        // Slide in stream
        stream.show('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });

        }
        }])

    .factory('HideStream', [ 'LoadBreadCrumbs', function(LoadBreadCrumbs) {
    return function() {
        // Remove the stream widget

        var stream = $('#stream-container');
        stream.hide('slide', {'direction': 'left'}, {'duration': 500, 'queue': false });

        // Completely destroy the container so we don't experience random flashes of it later.
        // There was some sort of weirdness with the tab 'show' causing the stream to slide in when
        // a tab was clicked, after the stream had been hidden. Seemed like timing- wait long enough
        // before clicking a tab, and it would not happen.
        setTimeout( function() {
           stream.detach();
           stream.empty();
           stream.unbind();
           $('#tab-content-container').css({ 'min-height': 0 }); //let the parent height go back to normal
           }, 500);

        LoadBreadCrumbs();
        }
        }])

    .factory('StreamBreadCrumbs', ['$rootScope', '$location', function($rootScope, $location) {
    return function() {
        // Load the breadcrumbs array. We have to do things a bit different than Utilities.LoadBreadcrumbs.
        // Rather than botch that all up, we'll do our own thing here.
        $rootScope.breadcrumbs = [];
        var paths = $location.path().split('/');
        paths.splice(0,1);
        var path, title;
        for (var i=0; i < paths.length; i++) {
            if (/^\d+/.test(paths[i])) {
                path='';
                title='';
                for (j=0; j <= i; j++) {
                    path += '/' + paths[j];
                }
                for (j=0; j < $rootScope.crumbCache.length; j++) {
                    if ($rootScope.crumbCache[j].path == path) {
                        title = $rootScope.crumbCache[j].title;
                        break;
                    }
                }
                if (!title) {
                    title = paths[i - 1].substr(0,paths[i - 1].length - 1);
                    title = (title == 'inventorie') ? 'inventory' : title;
                }
            }
            else {
                path='';
                title='';
                if (i > 0) {
                    for (j=0; j <= i; j++) {
                        path += '/' + paths[j];
                    }
                }
                else {
                   path = '/' + paths[i];
                }
                title = paths[i];
            }
            $rootScope.breadcrumbs.push({ path: path, title: title, ngClick: "closeStream('" + path + "')" });
        }
        }
        }])

    .factory('FixUrl', [ function() {
    return function(u) {
        return u.replace(/\/api\/v1\//,'/#/');
        }
        }])

    .factory('BuildUrl', [ function() {
    return function(obj) {
        var url = '/#/';
        switch(obj.base) {
           case 'group':
           case 'host':
               url += 'home/' + obj.base + 's/?name=' + obj.name;
               break;
           case 'inventory':
               url += 'inventories/' + obj.id;
               break;
           default:
               url += obj.base + 's/' + obj.id;
        }
        return url;
        }
        }])

    .factory('BuildDescription', ['FixUrl', 'BuildUrl', function(FixUrl, BuildUrl) {
    return function(activity) {
        var descr = '';
        var descr_nolink;
        descr += activity.operation;
        descr += (/e$/.test(activity.operation)) ? 'd ' : 'ed ';
        descr_nolink = descr;
        var obj1 = activity.object1;
        var obj2 = activity.object2;
        if (activity.summary_fields[obj2] && activity.summary_fields[obj2][0].name) {
            activity.summary_fields[obj2][0]['base'] = obj2;
            descr += obj2 + ' '
                + activity.summary_fields[obj2][0].name + '' + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
            descr_nolink += obj2 + ' ' + activity.summary_fields[obj2][0].name + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
        }
        else if (activity.object2) {
            descr += activity.object2[0] + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
            descr_nolink += activity.object2[0] + ( (activity.operation == 'disassociate') ? ' from ' : ' to ' );
        }
        if (activity.summary_fields[obj1] && activity.summary_fields[obj1][0].name) {
            activity.summary_fields[obj1][0]['base'] = obj1;
            descr += obj1 + ' '
                + activity.summary_fields[obj1][0].name + '';
            descr_nolink += obj1 + ' ' + activity.summary_fields[obj1][0].name;
        }
        else if (activity.object1) {
            descr += activity.object1;
            descr_nolink += activity.object1;
        }
        activity['description'] = descr;
        activity['description_nolink'] = descr_nolink;
        }
        }])

    .factory('ShowDetail', ['$rootScope', 'Rest', 'Alert', 'GenerateForm', 'ProcessErrors', 'GetBasePath', 'FormatDate',
        'ActivityDetailForm', 'Empty', 'Find',
    function($rootScope, Rest, Alert, GenerateForm, ProcessErrors, GetBasePath, FormatDate, ActivityDetailForm, Empty, Find) {
    return function(params) {

        var activity_id = params.activity_id;
        var parent_scope = params.scope;

        var generator = GenerateForm;
        var form = ActivityDetailForm;
        var activity = Find({list: parent_scope.activities, key: 'id', val: activity_id });

        if (activity) {
            // Setup changes field
            activity['changes_stringified'] = JSON.stringify(activity['changes'], null, '\t');
            var n = activity['changes_stringified'].match(/\n/g);
            var rows = (n) ? n.length : 1;
            rows = (rows < 1) ? 3 : 10;
            form.fields['changes'].rows = 10;

            // Load the form
            var scope = generator.inject(form, { mode: 'edit', modal: true, related: false });
            scope['changes'] = activity['changes_stringified'];
            scope['user'] = ( (activity.summary_fields.actor) ? activity.summary_fields.actor.username : 'system' ) +
                ' on ' + FormatDate(new Date(activity['timestamp']));
            scope['operation'] = activity['description_nolink'];

            scope.formModalAction = function() {
                $('#form-modal').modal("hide");
                }

            $('#form-modal').on('show.bs.modal', function (e) {
                $('#form-modal-body').css({
                    width:'auto',  //probably not needed
                    height:'auto', //probably not needed
                    'max-height':'100%'
                    });
                });

            scope.formModalActionLabel = 'OK';
            scope.formModalCancelShow = false;
            scope.formModalInfo = false;
            scope.formModalHeader = "Event " + activity.id;

            if (!scope.$$phase) {
               scope.$digest();
            }
        }

        }
        }])

    .factory('Stream', ['$rootScope', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait', 'StreamList', 'SearchInit',
        'PaginateInit', 'GenerateList', 'FormatDate', 'ShowStream', 'HideStream', 'BuildDescription', 'FixUrl', 'BuildUrl',
        'ShowDetail', 'StreamBreadCrumbs', 'setStreamHeight', 'Find',
    function($rootScope, $location, Rest, GetBasePath, ProcessErrors, Wait, StreamList, SearchInit, PaginateInit, GenerateList,
        FormatDate, ShowStream, HideStream, BuildDescription, FixUrl, BuildUrl, ShowDetail, StreamBreadCrumbs, setStreamHeight,
        Find) {
    return function(params) {

        var list = StreamList;
        var defaultUrl = GetBasePath('activity_stream');
        var view = GenerateList;
        var base = $location.path().replace(/^\//,'').split('/')[0];

        // pass in an inventory name to fix breadcrumb display
        var inventory_name = (params) ? params.inventory_name : null;

        // url will override the attempt to compute an activity_stream query
        var url = (params) ? params.url : null;

        $rootScope.flashMessage = null;

        if (url) {
            defaultUrl = url;
        }
        else {
            if ($location.path() !== '/home') {
                // Restrict what we're looking at based on the path
                var type = (base == 'inventories') ? 'inventory' : base.replace(/s$/,'');
                var paths = $location.path().split('/');
                paths.splice(0,1);
                if (paths.length > 1 && /^\d+/.test(paths[paths.length - 1])) {
                    type = paths[paths.length - 2];
                    type = (type == 'inventories') ? 'inventory' : type.replace(/s$/,'');
                    //defaultUrl += '?object1=' + type + '&object1__id=' +
                    defaultUrl += '?' + type + '__id=' + paths[paths.length - 1];
                }
                else if (paths.length > 1) {
                    type = paths[paths.length - 1];
                    type = (type == 'inventories') ? 'inventory' : type.replace(/s$/,'');
                    defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
                }
                else {
                    defaultUrl += '?or__object1=' + type + '&or__object2=' + type;
                }
            }
        }

        // Add a container for the stream widget
        $('#tab-content-container').append('

');

        StreamBreadCrumbs();

        // Fix inventory name. The way we're doing breadcrumbs doesn't support bind variables.
        if (inventory_name) {
            var itm = Find({ list: $rootScope.breadcrumbs, key: 'title', val: '{{ inventory_name }}' });
            if (itm) {
                itm.title = inventory_name;
            }
        }

        ShowStream();

        // Generate the list
        var scope = view.inject(list, {
            mode: 'edit',
            id: 'stream-content',
            searchSize: 'col-lg-3',
            secondWidget: true,
            activityStream: true
            });

        scope.closeStream = function(inUrl) {
            HideStream();
            if (scope.searchCleanup)
                scope.searchCleanup();
            if (inUrl)
               $location.path(inUrl);
            }

        scope.refreshStream = function() {
            scope.search(list.iterator);
            }

        scope.showDetail = function(id) {
            ShowDetail({ scope: scope, activity_id: id });
            }

        if (scope.removeStreamPostRefresh) {
            scope.removeStreamPostRefresh();
        }
        scope.removeStreamPostRefresh = scope.$on('PostRefresh', function() {
            for (var i=0; i < scope['activities'].length; i++) {
                // Convert event_time date to local time zone
                cDate = new Date(scope['activities'][i].timestamp);
                scope['activities'][i].timestamp = FormatDate(cDate);

                // Display username
                /*scope['activities'][i].user = (scope['activities'][i].summary_fields.user) ? scope['activities'][i].summary_fields.user.username :
                    'system';
                if (scope['activities'][i].user !== 'system') {
                    // turn user into a link when not 'system'
                    scope['activities'][i].user = "" +
                        scope['activities'][i].user + "";
                }*/
                if (scope['activities'][i]['summary_fields']['actor']) {
                    scope['activities'][i]['user'] = "" +
                        scope['activities'][i]['summary_fields']['actor']['username'] + "";
                }
                else {
                    scope['activities'][i]['user'] = 'system';
                }

                // Objects
                var href;
                var deleted = /^\_delete/;
                var obj1 = scope['activities'][i].object1;
                var obj2 = scope['activities'][i].object2;
                if ( obj1 && scope['activities'][i].summary_fields[obj1] && scope['activities'][i].summary_fields[obj1].name) {
                    if ( !deleted.test(scope['activities'][i].summary_fields[obj1].name) ) {
                        href = BuildUrl(scope['activities'][i].summary_fields.object1);
                        scope['activities'][i].objects = "" + scope['activities'][i].summary_fields[obj1].name + "";
                    }
                    else {
                        scope['activities'][i].objects = scope['activities'][i].summary_fields[obj1].name;
                    }
                }
                else if (scope['activities'][i].object1) {
                    scope['activities'][i].objects = scope['activities'][i].object1;
                }
                if (obj2 && scope['activities'][i].summary_fields[obj2] && scope['activities'][i].summary_fields[obj2].name) {
                    if ( !deleted.test(scope['activities'][i].summary_fields.object2.name) ) {
                        href = BuildUrl(scope['activities'][i].summary_fields.object2);
                        scope['activities'][i].objects += ", " + scope['activities'][i].summary_fields[obj2].name + "";
                    }
                    else {
                        scope['activities'][i].objects += "," + scope['activities'][i].summary_fields[obj2].name;
                    }
                }
                else if (scope['activities'][i].object2) {
                    scope['activities'][i].objects += ", " + scope['activities'][i].object2;
                }

                BuildDescription(scope['activities'][i]);

            }
            // Give ng-repeate a chance to show the data before adjusting the page size.
            setTimeout(function() { setStreamHeight(); }, 500);
            });

        // Initialize search and paginate pieces and load data
        SearchInit({ scope: scope, set: list.name, list: list, url: defaultUrl });
        PaginateInit({ scope: scope, list: list, url: defaultUrl });
        scope.search(list.iterator);

        }
        }]);
    <|endoftext|>


<commit_before>// PostProvider using memory storage

var _           = require('underscore'),
    when        = require('when'),
    nodefn      = require('when/node/function'),
    cfg         = require('nconf'),
    fs          = require('fs'),
    path        = require('path'),
    moment      = require('moment'),
    idGen       = require('../idgenerator');
    isAbsolute  = require('../../utils').isAbsolute,
    dateProps   = ['publishedAt', 'createdAt', 'updatedAt'];

var PostProvider = module.exports = function () {
    this.dummyData = [];
};

PostProvider.prototype.init = function () {
    return this.loadFiles();
};

PostProvider.prototype.loadFiles = function () {
    var that        = this,
        postsPath   = cfg.get('database:postsFile'),
        usersPath   = cfg.get('database:usersFile'),
        postsFile   = isAbsolute(postsPath) ? postsPath : path.join(cfg.get('paths:data'), postsPath),
        usersFile   = isAbsolute(usersPath) ? usersPath : path.join(cfg.get('paths:data'), usersPath),
        loadPosts   = nodefn.call(fs.readFile, postsFile),
        loadUsers   = nodefn.call(fs.readFile, usersFile);

    return when
        .join(loadPosts, loadUsers)                 // load data files
        .then(function (values) {                   // parse each file to JSON
            return when.map(values, JSON.parse);
        })
        .spread(function (posts, users) {           // set internal properties
            that.dummyData = posts;
            that.users = users;
        })
        .then(convertDateProperties.bind(that))     // convert date properties
        .then(updateAuthorInfo.bind(that));         // update users (authors)
    };

PostProvider.prototype.create = function(post) {
    post._id = idGen();

    this.dummyData.push(post);

    console.info('created post ... ', post);
    console.info('all posts', this.dummyData.length);

    return when.resolve(post._id);
};

/*
 * Find all posts
 */
PostProvider.prototype.findAll = function (opts) {
    return sortAndSlice(select(this.dummyData, opts), opts);
};

/*
 * Finds a single post by slug
 */
PostProvider.prototype.findBySlug = function (slug, opts) {
    var chain = _.chain(this.dummyData).filter(function (post) {
        return post.slug === slug;
    });

    return when.resolve(updateSelection(chain, opts).first().value());
};

/*
 * Finds a single post by id
 */
PostProvider.prototype.findById = function (id, opts) {
    var chain = _.chain(this.dummyData).filter(function (post) {
        return post._id === id;
    });

    return when.resolve(updateSelection(chain, opts).first().value());
};

/*
 * Finds posts at a given date range (from start to end of a year, or a month, or a day)
 */
PostProvider.prototype.findByDate = function (opts) {
    return sortAndSlice(select(this.dummyData, opts), opts);
};

PostProvider.prototype.findByLabel = function (opts) {
    if (!opts.label) return when.resolve([]);

    return sortAndSlice(select(this.dummyData, opts), opts);
};

PostProvider.prototype.count = function (opts) {
    return when.resolve(select(this.dummyData, opts).length);
};

function updateSelection (chain, opts) {
    if (!opts) return chain;

    var now = Date.now();

    if (opts.live || 'live' === opts.type) {
        chain = chain.filter(function (post) {
            return post.publishedAt <= now;
        });
    }

    if('undefined' !== typeof opts.page) {
        chain = chain.filter(function (post) {
            return post.page === opts.page;
        });
    }

    return chain;
}

function select(posts, opts) {
    opts = opts || {};

    var month = (opts.month || 1) - 1, // JavaScript Date uses 0-based month index
        now = new Date(),
        chain = _.chain(posts);

    chain = updateSelection(chain, opts);

    if (opts.label) {
        chain = chain.filter(function (post) {
            return post.labels && post.labels.indexOf(opts.label) >= 0;
        });
    }

    if (opts.year) {
        chain = chain.filter(function (post) {
            return post.publishedAt && post.publishedAt.getFullYear() === opts.year;
        });
    }

    if (opts.month) {
        chain = chain.filter(function (post) {
            return post.publishedAt && post.publishedAt.getMonth() === month;
        });
    }

    if (opts.day) {
        chain = chain.filter(function (post) {
            return post.publishedAt && post.publishedAt.getDate() === opts.day;
        });
    }

    if ('draft' === opts.type) {
        chain = chain.filter(function (post) {
            return !post.publishedAt;
        });
    }

    if ('scheduled' === opts.type) {
        chain = chain.filter(function (post) {
            return post.publishedAt > now;
        });
    }

    return chain.value();
}

PostProvider.prototype.postCountInfo = function (opts) {
    var items, now = Date.now(),
        chain = updateSelection(_.chain(this.dummyData), opts),
        count = chain.reduce(function (count, post) {
            if (!post.publishedAt) count.draft++;
            else if (post.publishedAt > now) count.scheduled++;
            else count.live++;

            return count;
        }, { all: 0, live: 0, draft: 0, scheduled: 0 }).value();

    count.all = count.live + count.scheduled + count.draft;

    return when.resolve(count);
};

PostProvider.prototype.archiveInfo = function (opts) {
    var posts = select(this.dummyData, opts);

    var info = _.chain(posts)
        .map(function (post) {
            return moment(post.publishedAt).startOf('month').valueOf();
        })
        .groupBy()
        .map(function (values, date) {
            return {
                dateMillisec: +date,
                date: moment(+date),
                count: values.length
            };
        })
        .sortBy(function (item) {
            return -item.dateMillisec;
        })
        .value();

    return when.resolve(info);
};

PostProvider.prototype.labelsInfo = function (opts) {
    var labels = _.chain(select(this.dummyData, opts))
        .map(function (post) {
            return post.labels;
        })
        .flatten()
        .countBy()
        .map(function (count, label) {
            return { label: label, count: count };
        })
        .sortBy(function (item) {
            return -item.count;
        })
        .value();

    return when.resolve(labels);
};

function sortAndSlice(posts, opts) {
    opts = opts || {};

    var start = opts.skip || 0,
    end = (opts.limit) ? start + opts.limit : undefined;

    return when.resolve(sort(posts, opts).slice(start, end));
}

function sort(posts, opts) {
    var reverse = false,
        sortBy = opts.sortBy || '-publishedAt';

    posts = posts.slice(0);

    if (sortBy[0] === '-') {
        reverse = true;
        sortBy = sortBy.slice(1);
    }

    posts = _.sortBy(posts, sortBy);

    if (reverse) {
        posts.reverse();
    }

    return posts;
}

function convertDateProperties () {
    this.dummyData.forEach(function (post) {
        dateProps.forEach(function (prop) {
            if (this[prop]) this[prop] = new Date(this[prop]);
        }, post);
    });
}

function updateAuthorInfo () {
    this.dummyData.forEach(function (post) {
        post.author = this.users[post._authorId];
    }, this);
}
<commit_msg>PostProvider API improvements<commit_after>// PostProvider using memory storage

var _           = require('underscore'),
    when        = require('when'),
    nodefn      = require('when/node/function'),
    cfg         = require('nconf'),
    fs          = require('fs'),
    path        = require('path'),
    moment      = require('moment'),
    idGen       = require('../idgenerator');
    isAbsolute  = require('../../utils').isAbsolute,
    dateProps   = ['publishedAt', 'createdAt', 'updatedAt'];

var PostProvider = module.exports = function () {
    this.dummyData = [];
};

// PostProvider
// init
// loadFiles - init
// create (properties)

// findAll (properties)
// findBySlug (slug)
// findById (id)
// findByDate (properties)
// findByLabel
// count (properties)
// archiveInfo
// labelsInfo
// postCountInfo

PostProvider.prototype.init = function () {
    return this.loadFiles();
};

PostProvider.prototype.loadFiles = function () {
    var that        = this,
        postsPath   = cfg.get('database:postsFile'),
        usersPath   = cfg.get('database:usersFile'),
        postsFile   = isAbsolute(postsPath) ? postsPath : path.join(cfg.get('paths:data'), postsPath),
        usersFile   = isAbsolute(usersPath) ? usersPath : path.join(cfg.get('paths:data'), usersPath),
        loadPosts   = nodefn.call(fs.readFile, postsFile),
        loadUsers   = nodefn.call(fs.readFile, usersFile);

    return when
        .join(loadPosts, loadUsers)                 // load data files
        .then(function (values) {                   // parse each file to JSON
            return when.map(values, JSON.parse);
        })
        .spread(function (posts, users) {           // set internal properties
            that.dummyData = posts;
            that.users = users;
        })
        .then(convertDateProperties.bind(that))     // convert date properties
        .then(updateAuthorInfo.bind(that));         // update users (authors)
    };

PostProvider.prototype.create = function(post) {
    post._id = idGen();

    this.dummyData.push(post);

    console.info('created post ... ', post);
    console.info('all posts', this.dummyData.length);

    return when.resolve(post._id);
};

/*
 * Find all posts
 */
PostProvider.prototype.findAll = function (opts) {
    return sortAndSlice(select(this.dummyData, opts), opts);
};

/*
 * Finds a single post by slug
 */
PostProvider.prototype.findBySlug = function (slug, opts) {
    var chain = _.chain(this.dummyData).filter(function (post) {
        return post.slug === slug;
    });

    return when.resolve(updateSelection(chain, opts).first().value());
};

/*
 * Finds a single post by id
 */
PostProvider.prototype.findById = function (id, opts) {
    var chain = _.chain(this.dummyData).filter(function (post) {
        return post._id === id;
    });

    return when.resolve(updateSelection(chain, opts).first().value());
};

/*
 * Finds posts at a given date range (from start to end of a year, or a month, or a day)
 */
PostProvider.prototype.findByDate = function (opts) {
    return sortAndSlice(select(this.dummyData, opts), opts);
};

PostProvider.prototype.findByLabel = function (opts) {
    if (!opts.label) return when.resolve([]);

    return sortAndSlice(select(this.dummyData, opts), opts);
};

PostProvider.prototype.count = function (opts) {
    return when.resolve(select(this.dummyData, opts).length);
};

function updateSelection (chain, opts) {
    if (!opts) return chain;

    var now = Date.now();

    if (opts.live || 'live' === opts.type) {
        chain = chain.filter(function (post) {
            return post.publishedAt <= now;
        });
    }

    if('undefined' !== typeof opts.page) {
        chain = chain.filter(function (post) {
            return post.page === opts.page;
        });
    }

    return chain;
}

function select(posts, opts) {
    opts = opts || {};

    var month = (opts.month || 1) - 1, // JavaScript Date uses 0-based month index
        now = new Date(),
        chain = _.chain(posts);

    chain = updateSelection(chain, opts);

    if (opts.label) {
        chain = chain.filter(function (post) {
            return post.labels && post.labels.indexOf(opts.label) >= 0;
        });
    }

    if (opts.year) {
        chain = chain.filter(function (post) {
            return post.publishedAt && post.publishedAt.getFullYear() === opts.year;
        });
    }

    if (opts.month) {
        chain = chain.filter(function (post) {
            return post.publishedAt && post.publishedAt.getMonth() === month;
        });
    }

    if (opts.day) {
        chain = chain.filter(function (post) {
            return post.publishedAt && post.publishedAt.getDate() === opts.day;
        });
    }

    if ('draft' === opts.type) {
        chain = chain.filter(function (post) {
            return !post.publishedAt;
        });
    }

    if ('scheduled' === opts.type) {
        chain = chain.filter(function (post) {
            return post.publishedAt > now;
        });
    }

    return chain.value();
}

PostProvider.prototype.postCountInfo = function (opts) {
    var items, now = Date.now(),
        chain = updateSelection(_.chain(this.dummyData), opts),
        count = chain.reduce(function (count, post) {
            if (!post.publishedAt) count.draft++;
            else if (post.publishedAt > now) count.scheduled++;
            else count.live++;

            return count;
        }, { all: 0, live: 0, draft: 0, scheduled: 0 }).value();

    count.all = count.live + count.scheduled + count.draft;

    return when.resolve(count);
};

PostProvider.prototype.archiveInfo = function (opts) {
    var posts = select(this.dummyData, opts);

    var info = _.chain(posts)
        .map(function (post) {
            return moment(post.publishedAt).startOf('month').valueOf();
        })
        .groupBy()
        .map(function (values, date) {
            return {
                dateMillisec: +date,
                date: moment(+date),
                count: values.length
            };
        })
        .sortBy(function (item) {
            return -item.dateMillisec;
        })
        .value();

    return when.resolve(info);
};

PostProvider.prototype.labelsInfo = function (opts) {
    var labels = _.chain(select(this.dummyData, opts))
        .map(function (post) {
            return post.labels;
        })
        .flatten()
        .countBy()
        .map(function (count, label) {
            return { label: label, count: count };
        })
        .sortBy(function (item) {
            return -item.count;
        })
        .value();

    return when.resolve(labels);
};

function sortAndSlice(posts, opts) {
    opts = opts || {};

    var start = opts.skip || 0,
    end = (opts.limit) ? start + opts.limit : undefined;

    return when.resolve(sort(posts, opts).slice(start, end));
}

function sort(posts, opts) {
    var reverse = false,
        sortBy = opts.sortBy || '-publishedAt';

    posts = posts.slice(0);

    if (sortBy[0] === '-') {
        reverse = true;
        sortBy = sortBy.slice(1);
    }

    posts = _.sortBy(posts, sortBy);

    if (reverse) {
        posts.reverse();
    }

    return posts;
}

function convertDateProperties () {
    this.dummyData.forEach(function (post) {
        dateProps.forEach(function (prop) {
            if (this[prop]) this[prop] = new Date(this[prop]);
        }, post);
    });
}

function updateAuthorInfo () {
    this.dummyData.forEach(function (post) {
        post.author = this.users[post._authorId];
    }, this);
}
<|endoftext|>


<commit_before>/**
 *  Handles fixtures' "Manage Tables" page.
 */
define([
    "jquery",
    "knockout",
    "hqwebapp/js/initial_page_data",
    "hqwebapp/js/hq.helpers",
], function(
    $,
    ko,
    initialPageData
) {
    "use strict";
    var somethingWentWrong = $("#FailText").text();
    function log (x) {
        return x;
    }
    function makeEditable(o) {
        o.saveState = ko.observable('saved');
        o.editing = ko.observable(false);
        o.startEditing = function () {
            o.editing(true);
            try {
                o._backup = o.serialize();
            } catch (e) {

            }
        };
        o.stopEdit = function () {
            o.editing(false);
        };
        o.cancelEdit = function () {
            o.editing(false);
            o.cancel();
        };
        o.saveEdit = function () {
            o.editing(false);
            log(o);
            o.save();
        };
        return o;
    }
    function makeDataType(o, app) {
        var self = ko.mapping.fromJS(o),
            raw_fields = self.fields();
            self.original_tag = self.tag();
            self.original_visibility = self.is_global();
            self.isVisible = ko.observable(true);
        self.fields = ko.observableArray([]);
        makeEditable(self);
        if (!o._id) {
            self._id = ko.observable();
        }
        self.view_link = ko.computed(function(){
            return initialPageData.reverse('fixture_interface_dispatcher') + "?table_id=" + self._id();
        }, self);
        self.aboutToDelete = ko.observable(false);
        self.addField = function (data, event, o) {
            var i, field;
            if (o) {
                field = {
                    tag: ko.observable(o.tag),
                    with_props: ko.observable(o.with_props),
                    original_tag: ko.observable(o.tag),
                    is_new: ko.observable(false),
                    remove: ko.observable(false),
                    editing: ko.observable(false)
                };
            } else {
                field = {
                    tag: ko.observable(""),
                    with_props: ko.observable(false),
                    original_tag: ko.observable(""),
                    is_new: ko.observable(true),
                    remove: ko.observable(false),
                    editing: ko.observable(true)
                };
            }
            field.isDuplicate = ko.computed(function () {
                var j, noRepeats = true;
                var curVal = field.tag();
                for (j = 0; j < self.fields().length; j += 1) {
                    var thatField = self.fields()[j];
                    if (thatField !== field && thatField.tag() === curVal) {
                        noRepeats = false;
                    }
                }
                return !noRepeats;
            });
            field.isBadSlug = ko.computed(function () {
                var patt = new RegExp("([/\\<> ])");
                return patt.test(field.tag());
            });
            field.noXMLStart = ko.computed(function () {
                var curVal = field.tag();
                return curVal.startsWith('xml');
            });
            field.remove_if_new = function(){
                if (field.is_new() == true){
                    self.fields.remove(field);
                }
            };
            self.fields.push(field);
        };
        for (var i = 0; i < raw_fields.length; i += 1) {
            var tag = raw_fields[i].field_name();
            var with_props = (raw_fields[i].properties().length == 0) ? false : true;
            self.addField(undefined, undefined, {tag: tag, with_props: with_props});
        }

        self.save = function () {
            $.ajax({
                type: self._id() ? (self._destroy ? 'delete' : 'put') : 'post',
                url: initialPageData.reverse('update_lookup_tables') + (self._id() || ''),
                data: JSON.stringify(self.serialize()),
                dataType: 'json',
                error: function(data) {
                    var error_message;
                    if (data.responseText == "DuplicateFixture"){
                        error_message = "Can not create table with ID '"+self.tag()+"'. Table IDs should be unique.";
                    }
                    else{
                        error_message = somethingWentWrong;
                    }
                    $("#FailText").text(error_message);
                    $("#editFailure").removeClass('hide');
                    self.cancel();
                    self.saveState('saved');
                    },
                success: function (data) {
                    if (data.validation_errors) {
                        var $failMsg = $("<p />").text(data.error_msg);
                        var $failList = $("<ul />");
                        for (var v=0; v < data.validation_errors.length; v++) {
                            $failList.append($("<li />").text(data.validation_errors[v]));
                        }
                        $("#FailText")
                            .text('')
                            .append($failMsg)
                            .append($failList);
                        $("#editFailure").removeClass('hide');
                        self.cancel();
                        self.saveState('saved');
                        return;
                    }
                    self.saveState('saved');
                    if (!self._id()) {
                        self._id(data._id);
                    }
                    self.original_visibility = self.is_global();
                    self.original_tag = self.tag();
                    var keptFields = [];
                    for (var i = 0; i < self.fields().length; i += 1) {
                        var field = self.fields()[i];
                        if (!field.remove()) {
                            field.original_tag(field.tag());
                            field.is_new(false);
                            keptFields.push(field);
                        }
                    }
                    self.fields(keptFields);
                }
            });
            self.saveState('saving');
        };
        self.cancel = function () {
            var indicesToRemoveAt = [];
            self.tag(self.original_tag);
            self.is_global(self.original_visibility);
            if (!self._id()) {
                self.isVisible(false);
                app.removeBadDataType(self);
            } else {
                for (var i = 0; i < self.fields().length; i += 1) {
                    var field = self.fields()[i];
                    if (field.is_new() === true){
                        indicesToRemoveAt.push(i);
                        continue;
                    }
                    field.tag(field.original_tag());
                    field.remove(false);
                }
                for (var j = 0; j < indicesToRemoveAt.length; j += 1){
                    var index = indicesToRemoveAt[j];
                    self.fields.remove(self.fields()[index]);
                }
            }
        };
        self.serialize = function () {
            return log({
                _id: self._id(),
                tag: self.tag(),
                view_link: self.view_link(),
                is_global: self.is_global(),
                fields: (function () {
                    var fields = {}, i;
                    for (i = 0; i < self.fields().length; i += 1) {
                        var field = self.fields()[i];
                        var patch;
                        if (field.is_new() == true) {
                            if (field.remove() == true) continue;
                            patch = {"is_new": 1};
                            fields[field.tag()] = patch;
                        }
                        else if (field.remove() === true) {
                            patch = {"remove": 1};
                            fields[field.original_tag()] = patch;
                        }
                        else if (field.tag() !== field.original_tag()){
                            patch = {"update": field.tag()};
                            fields[field.original_tag()] = patch;
                        }
                        else {
                            patch = {};
                            fields[field.tag()] = patch;
                        }
                    }
                    return fields;
                }())
            });
        };
        return self;
    }
    function App() {
        var self = this;
        self.data_types = ko.observableArray([]);
        self.loading = ko.observable(0);
        self.file = ko.observable();
        self.selectedTables = ko.observableArray([]);

        self.removeBadDataType = function (dataType) {
            setTimeout(function () {
                // This needs to be here otherwise if you remove the dataType
                // directly from the dataType, the DOM freezes and the page
                // can't scroll.
                self.data_types.remove(dataType);
            }, 1000);
        };

        self.updateSelectedTables = function(element, event) {
            var $elem = $(event.srcElement || event.currentTarget);
            var $checkboxes = $(".select-bulk");
            if ($elem.hasClass("toggle")){
                self.selectedTables.removeAll();
                if ($elem.data("all")) {
                    $.each($checkboxes, function() {
                        $(this).prop("checked", true);
                        self.selectedTables.push(this.value);
                    });
                }
                else {
                    $.each($checkboxes, function() {
                        $(this).prop("checked", false);
                    });
                }
            }
            if ($elem.hasClass("select-bulk")) {
                var table_id = $elem[0].value;
                if ($elem[0].checked) {
                    self.selectedTables.push(table_id);
                }
                else {
                    self.selectedTables.splice(self.selectedTables().indexOf(table_id), 1);
                }
            }
        };

        self.downloadExcels = function(element, event) {
            var tables = [];
            if (self.selectedTables().length < 1)
                return;
            for (var i in self.selectedTables()) {
                tables.push(self.selectedTables()[i]);
            }
            $("#fixture-download").modal();
            if (tables.length > 0){
                // POST, because a long querystring can overflow the request
                $.ajax({
                    url: initialPageData.reverse('download_fixtures'),
                    type: 'POST',
                    data: {'table_ids': tables},
                    dataType: 'json',
                    success: function (response) {
                        self.setupDownload(response);
                    },
                    error: function (response) {
                        self.downloadError();
                    }
                });
            }
        };

        self.setupDownload = function (response) {
            var keep_polling = true;
            function poll() {
                if (keep_polling) {
                    $.ajax({
                        url: response.download_url,
                        dataType: 'text',
                        success: function (resp) {
                            var progress = $("#download-progress");
                            if (resp.replace(/[ \t\n]/g, '')) {
                                $("#downloading").addClass('hide');
                                progress.removeClass('hide').html(resp);
                                if (progress.find(".alert-success").length) {
                                    keep_polling = false;
                                }
                            }
                            if (keep_polling) {
                                setTimeout(poll, 2000);
                            }
                        },
                        error: function () {
                            self.downloadError();
                            keep_polling = false;
                        }
                    });
                }
            }
            $("#fixture-download").on("hide.bs.modal", function() {
                // stop polling if dialog is closed
                keep_polling = false;
            });
            $("#download-progress").addClass('hide');
            $("#downloading").removeClass('hide');
            poll();
        };

        self.downloadError = function () {
            var error_message = "Sorry, something went wrong with the download. If you see this repeatedly please report an issue."
            $("#fixture-download").modal("hide");
            $("#FailText").text(error_message);
            $("#editFailure").removeClass('hide');
        };

        self.addDataType = function () {
            var dataType = makeDataType({
                tag: "",
                fields: ko.observableArray([]),
                is_global: true
            }, self);
            dataType.editing(true);
            self.data_types.push(dataType);
        };
        self.removeDataType = function (dataType) {
            if (confirm("Are you sure you want to delete the table '" + dataType.tag() + "'?")){
                self.data_types.destroy(dataType);
                dataType.save();
            }
            return false;
        };
        self.loadData = function () {
            self.loading(self.loading() + 3);
            $.ajax({
                url: initialPageData.reverse('fixture_data_types'),
                type: 'get',
                dataType: 'json',
                success: function (data) {
                    var dataType;
                    for (var i = 0; i < data.length; i += 1) {
                        self.data_types.push(makeDataType(data[i], self));
                        dataType = self.data_types()[i];
                    }
                    self.loading(self.loading() - 1);
                }
            });
        };
    }

    var el = $('#fixtures-ui');
    var app = new App();
    el.koApplyBindings(app);
    el.removeClass('hide');
    app.loadData();
    $('#fixture-upload').koApplyBindings(app);
    $("#fixture-download").on("hidden.bs.modal", function(){
                    $("#downloading").removeClass('hide');
                    $("#download-progress").addClass('hide');
                    $("#download-complete").addClass('hide');
    });
    $('.alert .close').on("click", function(e) {
        $(this).parent().addClass('hide');
    });
});
<commit_msg>Include knockout_bindings.ko on manage tables page for the sake of modal binding<commit_after>/**
 *  Handles fixtures' "Manage Tables" page.
 */
define([
    "jquery",
    "knockout",
    "hqwebapp/js/initial_page_data",
    "hqwebapp/js/hq.helpers",
    "hqwebapp/js/knockout_bindings.ko",
], function(
    $,
    ko,
    initialPageData
) {
    "use strict";
    var somethingWentWrong = $("#FailText").text();
    function log (x) {
        return x;
    }
    function makeEditable(o) {
        o.saveState = ko.observable('saved');
        o.editing = ko.observable(false);
        o.startEditing = function () {
            o.editing(true);
            try {
                o._backup = o.serialize();
            } catch (e) {

            }
        };
        o.stopEdit = function () {
            o.editing(false);
        };
        o.cancelEdit = function () {
            o.editing(false);
            o.cancel();
        };
        o.saveEdit = function () {
            o.editing(false);
            log(o);
            o.save();
        };
        return o;
    }
    function makeDataType(o, app) {
        var self = ko.mapping.fromJS(o),
            raw_fields = self.fields();
            self.original_tag = self.tag();
            self.original_visibility = self.is_global();
            self.isVisible = ko.observable(true);
        self.fields = ko.observableArray([]);
        makeEditable(self);
        if (!o._id) {
            self._id = ko.observable();
        }
        self.view_link = ko.computed(function(){
            return initialPageData.reverse('fixture_interface_dispatcher') + "?table_id=" + self._id();
        }, self);
        self.aboutToDelete = ko.observable(false);
        self.addField = function (data, event, o) {
            var i, field;
            if (o) {
                field = {
                    tag: ko.observable(o.tag),
                    with_props: ko.observable(o.with_props),
                    original_tag: ko.observable(o.tag),
                    is_new: ko.observable(false),
                    remove: ko.observable(false),
                    editing: ko.observable(false)
                };
            } else {
                field = {
                    tag: ko.observable(""),
                    with_props: ko.observable(false),
                    original_tag: ko.observable(""),
                    is_new: ko.observable(true),
                    remove: ko.observable(false),
                    editing: ko.observable(true)
                };
            }
            field.isDuplicate = ko.computed(function () {
                var j, noRepeats = true;
                var curVal = field.tag();
                for (j = 0; j < self.fields().length; j += 1) {
                    var thatField = self.fields()[j];
                    if (thatField !== field && thatField.tag() === curVal) {
                        noRepeats = false;
                    }
                }
                return !noRepeats;
            });
            field.isBadSlug = ko.computed(function () {
                var patt = new RegExp("([/\\<> ])");
                return patt.test(field.tag());
            });
            field.noXMLStart = ko.computed(function () {
                var curVal = field.tag();
                return curVal.startsWith('xml');
            });
            field.remove_if_new = function(){
                if (field.is_new() == true){
                    self.fields.remove(field);
                }
            };
            self.fields.push(field);
        };
        for (var i = 0; i < raw_fields.length; i += 1) {
            var tag = raw_fields[i].field_name();
            var with_props = (raw_fields[i].properties().length == 0) ? false : true;
            self.addField(undefined, undefined, {tag: tag, with_props: with_props});
        }

        self.save = function () {
            $.ajax({
                type: self._id() ? (self._destroy ? 'delete' : 'put') : 'post',
                url: initialPageData.reverse('update_lookup_tables') + (self._id() || ''),
                data: JSON.stringify(self.serialize()),
                dataType: 'json',
                error: function(data) {
                    var error_message;
                    if (data.responseText == "DuplicateFixture"){
                        error_message = "Can not create table with ID '"+self.tag()+"'. Table IDs should be unique.";
                    }
                    else{
                        error_message = somethingWentWrong;
                    }
                    $("#FailText").text(error_message);
                    $("#editFailure").removeClass('hide');
                    self.cancel();
                    self.saveState('saved');
                    },
                success: function (data) {
                    if (data.validation_errors) {
                        var $failMsg = $("<p />").text(data.error_msg);
                        var $failList = $("<ul />");
                        for (var v=0; v < data.validation_errors.length; v++) {
                            $failList.append($("<li />").text(data.validation_errors[v]));
                        }
                        $("#FailText")
                            .text('')
                            .append($failMsg)
                            .append($failList);
                        $("#editFailure").removeClass('hide');
                        self.cancel();
                        self.saveState('saved');
                        return;
                    }
                    self.saveState('saved');
                    if (!self._id()) {
                        self._id(data._id);
                    }
                    self.original_visibility = self.is_global();
                    self.original_tag = self.tag();
                    var keptFields = [];
                    for (var i = 0; i < self.fields().length; i += 1) {
                        var field = self.fields()[i];
                        if (!field.remove()) {
                            field.original_tag(field.tag());
                            field.is_new(false);
                            keptFields.push(field);
                        }
                    }
                    self.fields(keptFields);
                }
            });
            self.saveState('saving');
        };
        self.cancel = function () {
            var indicesToRemoveAt = [];
            self.tag(self.original_tag);
            self.is_global(self.original_visibility);
            if (!self._id()) {
                self.isVisible(false);
                app.removeBadDataType(self);
            } else {
                for (var i = 0; i < self.fields().length; i += 1) {
                    var field = self.fields()[i];
                    if (field.is_new() === true){
                        indicesToRemoveAt.push(i);
                        continue;
                    }
                    field.tag(field.original_tag());
                    field.remove(false);
                }
                for (var j = 0; j < indicesToRemoveAt.length; j += 1){
                    var index = indicesToRemoveAt[j];
                    self.fields.remove(self.fields()[index]);
                }
            }
        };
        self.serialize = function () {
            return log({
                _id: self._id(),
                tag: self.tag(),
                view_link: self.view_link(),
                is_global: self.is_global(),
                fields: (function () {
                    var fields = {}, i;
                    for (i = 0; i < self.fields().length; i += 1) {
                        var field = self.fields()[i];
                        var patch;
                        if (field.is_new() == true) {
                            if (field.remove() == true) continue;
                            patch = {"is_new": 1};
                            fields[field.tag()] = patch;
                        }
                        else if (field.remove() === true) {
                            patch = {"remove": 1};
                            fields[field.original_tag()] = patch;
                        }
                        else if (field.tag() !== field.original_tag()){
                            patch = {"update": field.tag()};
                            fields[field.original_tag()] = patch;
                        }
                        else {
                            patch = {};
                            fields[field.tag()] = patch;
                        }
                    }
                    return fields;
                }())
            });
        };
        return self;
    }
    function App() {
        var self = this;
        self.data_types = ko.observableArray([]);
        self.loading = ko.observable(0);
        self.file = ko.observable();
        self.selectedTables = ko.observableArray([]);

        self.removeBadDataType = function (dataType) {
            setTimeout(function () {
                // This needs to be here otherwise if you remove the dataType
                // directly from the dataType, the DOM freezes and the page
                // can't scroll.
                self.data_types.remove(dataType);
            }, 1000);
        };

        self.updateSelectedTables = function(element, event) {
            var $elem = $(event.srcElement || event.currentTarget);
            var $checkboxes = $(".select-bulk");
            if ($elem.hasClass("toggle")){
                self.selectedTables.removeAll();
                if ($elem.data("all")) {
                    $.each($checkboxes, function() {
                        $(this).prop("checked", true);
                        self.selectedTables.push(this.value);
                    });
                }
                else {
                    $.each($checkboxes, function() {
                        $(this).prop("checked", false);
                    });
                }
            }
            if ($elem.hasClass("select-bulk")) {
                var table_id = $elem[0].value;
                if ($elem[0].checked) {
                    self.selectedTables.push(table_id);
                }
                else {
                    self.selectedTables.splice(self.selectedTables().indexOf(table_id), 1);
                }
            }
        };

        self.downloadExcels = function(element, event) {
            var tables = [];
            if (self.selectedTables().length < 1)
                return;
            for (var i in self.selectedTables()) {
                tables.push(self.selectedTables()[i]);
            }
            $("#fixture-download").modal();
            if (tables.length > 0){
                // POST, because a long querystring can overflow the request
                $.ajax({
                    url: initialPageData.reverse('download_fixtures'),
                    type: 'POST',
                    data: {'table_ids': tables},
                    dataType: 'json',
                    success: function (response) {
                        self.setupDownload(response);
                    },
                    error: function (response) {
                        self.downloadError();
                    }
                });
            }
        };

        self.setupDownload = function (response) {
            var keep_polling = true;
            function poll() {
                if (keep_polling) {
                    $.ajax({
                        url: response.download_url,
                        dataType: 'text',
                        success: function (resp) {
                            var progress = $("#download-progress");
                            if (resp.replace(/[ \t\n]/g, '')) {
                                $("#downloading").addClass('hide');
                                progress.removeClass('hide').html(resp);
                                if (progress.find(".alert-success").length) {
                                    keep_polling = false;
                                }
                            }
                            if (keep_polling) {
                                setTimeout(poll, 2000);
                            }
                        },
                        error: function () {
                            self.downloadError();
                            keep_polling = false;
                        }
                    });
                }
            }
            $("#fixture-download").on("hide.bs.modal", function() {
                // stop polling if dialog is closed
                keep_polling = false;
            });
            $("#download-progress").addClass('hide');
            $("#downloading").removeClass('hide');
            poll();
        };

        self.downloadError = function () {
            var error_message = "Sorry, something went wrong with the download. If you see this repeatedly please report an issue."
            $("#fixture-download").modal("hide");
            $("#FailText").text(error_message);
            $("#editFailure").removeClass('hide');
        };

        self.addDataType = function () {
            var dataType = makeDataType({
                tag: "",
                fields: ko.observableArray([]),
                is_global: true
            }, self);
            dataType.editing(true);
            self.data_types.push(dataType);
        };
        self.removeDataType = function (dataType) {
            if (confirm("Are you sure you want to delete the table '" + dataType.tag() + "'?")){
                self.data_types.destroy(dataType);
                dataType.save();
            }
            return false;
        };
        self.loadData = function () {
            self.loading(self.loading() + 3);
            $.ajax({
                url: initialPageData.reverse('fixture_data_types'),
                type: 'get',
                dataType: 'json',
                success: function (data) {
                    var dataType;
                    for (var i = 0; i < data.length; i += 1) {
                        self.data_types.push(makeDataType(data[i], self));
                        dataType = self.data_types()[i];
                    }
                    self.loading(self.loading() - 1);
                }
            });
        };
    }

    var el = $('#fixtures-ui');
    var app = new App();
    el.koApplyBindings(app);
    el.removeClass('hide');
    app.loadData();
    $('#fixture-upload').koApplyBindings(app);
    $("#fixture-download").on("hidden.bs.modal", function(){
                    $("#downloading").removeClass('hide');
                    $("#download-progress").addClass('hide');
                    $("#download-complete").addClass('hide');
    });
    $('.alert .close').on("click", function(e) {
        $(this).parent().addClass('hide');
    });
});
<|endoftext|>


<commit_before>define("Ti/Network/HTTPClient", ["Ti/_/Evented"], function(Evented) {

	Ti._5.createClass("Ti.Network.HTTPClient", function(args){

		var undef,
			obj = this,
			is = require.is,
			on = require.on,
			xhr = new XMLHttpRequest,
			UNSENT = 0,
			OPENED = 1,
			HEADERS_RECEIVED = 2,
			LOADING = 3,
			DONE = 4,
			_readyState = UNSENT, // unsent
			timeoutTimer;

		Ti._5.EventDriven(obj);

		function fireStateChange() {
			is(obj.onreadystatechange, "Function") && obj.onreadystatechange.call(obj);
		}

		xhr.onreadystatechange = function() {
			switch (xhr.readyState) {
				case 0: _readyState = UNSENT; break;
				case 1: _readyState = OPENED; break;
				case 2: _readyState = LOADING; break;
				case 3: _readyState = HEADERS_RECEIVED; break;
				case 4:
					clearTimeout(timeoutTimer);
					_readyState = DONE;
					if (xhr.status == 200) {
						obj.responseText = xhr.responseText;
						obj.responseXML = xhr.responseXML;
						obj.responseData = xhr.responceHeader;
						is(obj.onload, "Function") && obj.onload.call(obj);
					} else {
						xhr.status / 100 | 0 > 3 && onerror();
					}
			}
			fireStateChange();
		};

		function onerror(error) {
			obj.abort();
			is(error, "Object") || (error = { message: error });
			error.error || (error.error = error.message || xhr.status);
			parseInt(error.error) || (error.error = "Can't reach host");
			is(obj.onerror, "Function") && obj.onerror.call(obj, error);
		}

		on(xhr, "error", onerror);
		on(xhr.upload, "error", onerror);

		function onprogress(evt) {
			evt.progress = evt.lengthComputable ? evt.loaded / evt.total : false;
			is(obj.onsendstream, "Function") && obj.onsendstream.call(obj, evt);
		}

		on(xhr, "progress", onprogress);
		on(xhr.upload, "progress", onprogress);

		// Properties
		Ti._5.propReadOnly(obj, {
			UNSENT: UNSENT,
			OPENED: OPENED,
			HEADERS_RECEIVED: HEADERS_RECEIVED,
			LOADING: LOADING,
			DONE: DONE,
			connected: function() { return _readyState >= OPENED; },
			readyState: function() { return _readyState; },
			status: function() { return xhr.status; }
		});

		Ti._5.prop(obj, {
			connectionType: undef,
			file: undef,
			location: undef,
			ondatastream: undef,
			onerror: undef,
			onload: undef,
			onreadystatechange: undef,
			onsendstream: undef,
			responseData: "",
			responseText: "",
			responseXML: "",
			timeout: undef,
			validatesSecureCertificate: false
		});

		require.mix(obj, args);

		// Methods
		obj.abort = function() {
			obj.responseText = obj.responseXML = obj.responseData = "";
			clearTimeout(timeoutTimer);
			obj.connected && xhr.abort();
			_readyState = UNSENT;
			fireStateChange();
		};

		obj.getResponseHeader = function(name) {
			return xhr.readyState === 2 ? xhr.getResponseHeader(name) : null;
		};

		obj.open = function(method, url, async) {
			var httpURLFormatter = Ti.Network.httpURLFormatter;
			obj.abort();
			xhr.open(
				obj.connectionType = method,
				obj.location = require("Ti/_").getAbsolutePath(httpURLFormatter ? httpURLFormatter(url) : url),
				!!async
			);
			xhr.setRequestHeader("UserAgent", Ti.userAgent);
		};

		obj.send = function(args){
			try {
				xhr.send(args || null);
				clearTimeout(timeoutTimer);
				obj.timeout && (timeoutTimer = setTimeout(function() {
					if (obj.connected) {
						obj.abort();
						onerror("Request timed out");
					}
				}, obj.timeout));
			} catch (error) {
				onerror(error);
			}
		};

		obj.setRequestHeader = function(label,value) {
			xhr.setRequestHeader(label,value);
		};
	});

});<commit_msg>[TIMOB-6772] Added a networking hack.<commit_after>define("Ti/Network/HTTPClient", ["Ti/_/Evented"], function(Evented) {

	Ti._5.createClass("Ti.Network.HTTPClient", function(args){

		var undef,
			obj = this,
			is = require.is,
			on = require.on,
			xhr = new XMLHttpRequest,
			UNSENT = 0,
			OPENED = 1,
			HEADERS_RECEIVED = 2,
			LOADING = 3,
			DONE = 4,
			_readyState = UNSENT, // unsent
			_completed, // This completed stuff is a hack to get around a non-obvious bug.
			timeoutTimer;

		Ti._5.EventDriven(obj);

		function fireStateChange() {
			is(obj.onreadystatechange, "Function") && obj.onreadystatechange.call(obj);
		}

		xhr.onreadystatechange = function() {
			switch (xhr.readyState) {
				case 0: _readyState = UNSENT; break;
				case 1: _readyState = OPENED; break;
				case 2: _readyState = LOADING; break;
				case 3: _readyState = HEADERS_RECEIVED; break;
				case 4:
					clearTimeout(timeoutTimer);
					_completed = true;
					_readyState = DONE;
					if (xhr.status == 200) {
						obj.responseText = xhr.responseText;
						obj.responseXML = xhr.responseXML;
						obj.responseData = xhr.responceHeader;
						is(obj.onload, "Function") && obj.onload.call(obj);
					} else {
						xhr.status / 100 | 0 > 3 && onerror();
					}
			}
			fireStateChange();
		};

		function onerror(error) {
			obj.abort();
			is(error, "Object") || (error = { message: error });
			error.error || (error.error = error.message || xhr.status);
			parseInt(error.error) || (error.error = "Can't reach host");
			is(obj.onerror, "Function") && obj.onerror.call(obj, error);
		}

		on(xhr, "error", onerror);
		on(xhr.upload, "error", onerror);

		function onprogress(evt) {
			evt.progress = evt.lengthComputable ? evt.loaded / evt.total : false;
			is(obj.onsendstream, "Function") && obj.onsendstream.call(obj, evt);
		}

		on(xhr, "progress", onprogress);
		on(xhr.upload, "progress", onprogress);

		// Properties
		Ti._5.propReadOnly(obj, {
			UNSENT: UNSENT,
			OPENED: OPENED,
			HEADERS_RECEIVED: HEADERS_RECEIVED,
			LOADING: LOADING,
			DONE: DONE,
			connected: function() { return _readyState >= OPENED; },
			readyState: function() { return _readyState; },
			status: function() { return xhr.status; }
		});

		Ti._5.prop(obj, {
			connectionType: undef,
			file: undef,
			location: undef,
			ondatastream: undef,
			onerror: undef,
			onload: undef,
			onreadystatechange: undef,
			onsendstream: undef,
			responseData: "",
			responseText: "",
			responseXML: "",
			timeout: undef,
			validatesSecureCertificate: false
		});

		require.mix(obj, args);

		// Methods
		obj.abort = function() {
			obj.responseText = obj.responseXML = obj.responseData = "";
			_completed = true;
			clearTimeout(timeoutTimer);
			obj.connected && xhr.abort();
			_readyState = UNSENT;
			fireStateChange();
		};

		obj.getResponseHeader = function(name) {
			return xhr.readyState === 2 ? xhr.getResponseHeader(name) : null;
		};

		obj.open = function(method, url, async) {
			var httpURLFormatter = Ti.Network.httpURLFormatter;
			obj.abort();
			xhr.open(
				obj.connectionType = method,
				obj.location = require("Ti/_").getAbsolutePath(httpURLFormatter ? httpURLFormatter(url) : url),
				!!async
			);
			xhr.setRequestHeader("UserAgent", Ti.userAgent);
		};

		obj.send = function(args){
			_completed = false;
			try {
				xhr.send(args || null);
				clearTimeout(timeoutTimer);
				obj.timeout && (timeoutTimer = setTimeout(function() {
					if (obj.connected) {
						obj.abort();
						!_completed && onerror("Request timed out");
					}
				}, obj.timeout));
			} catch (error) {
				onerror(error);
			}
		};

		obj.setRequestHeader = function(label,value) {
			xhr.setRequestHeader(label,value);
		};
	});

});<|endoftext|>