<commit_before>/*global $, openerp, _, PDFJS */
$(document).ready(function () {

    "use strict";

    var website = openerp.website;
    var _t = openerp._t;

    website.slide.template = website.add_template_file('/website_slides/static/src/xml/website_slides.xml');

    website.slide.Dialog = openerp.Widget.extend({
        template: 'website.slide.upload',
        events: {
            'hidden.bs.modal': 'destroy',
            'click button.save': 'save',
            'click button[data-dismiss="modal"]': 'cancel',
            'change input#upload': 'slide_upload',
            'change input#url': 'slide_url',
            'click .list-group-item': function (ev) {
                this.$('.list-group-item').removeClass('active');
                $(ev.target).closest('li').addClass('active');
            }
        },
        init: function (el, channel_id) {
            this._super(el, channel_id);
            this.channel_id = parseInt(channel_id, 10);
            this.file = {};
            this.index_content = "";
        },
        start: function () {
            this.$el.modal({
                backdrop: 'static'
            });
            this.set_category_id();
            this.set_tag_ids();
        },
        slide_url: function (ev) {
            var self = this,
                value = {
                    'url': $(ev.target).val(),
                    'channel_id': self.channel_id
                };
            this.$('.alert-warning').remove();
            this.is_valid_url = false;
            this.$('.save').button('loading');
            openerp.jsonRpc('/slides/dialog_preview/', 'call', value).then(function (data) {
                self.$('.save').button('reset');
                if (data.error) {
                    self.display_alert(data.error);
                } else {
                    self.$("#slide-image").attr("src", data.url_src);
                    self.$('#name').val(data.title);
                    self.$('#description').val(data.description);
                    self.is_valid_url = true;
                }
            });
        },
        check_unique_slide: function (file_name) {
            var self = this;
            return openerp.jsonRpc('/web/dataset/call_kw', 'call', {
                model: 'slide.slide',
                method: 'search_count',
                args: [[['channel_id', '=', self.channel_id], ['name', '=', file_name]]],
                kwargs: {}
            });
        },
        slide_upload: function (ev) {
            var self = this,
                file = ev.target.files[0],
                is_image = /^image\/.*/.test(file.type),
                loaded = false;
            this.file.name = file.name;
            this.file.type = file.type;
            if (!(is_image || this.file.type === 'application/pdf')) {
                this.display_alert(_t("Invalid file type. Please select pdf or image file"));
                this.reset_file();
                return;
            }
            if (file.size / 1024 / 1024 > 15) {
                this.display_alert(_t("File is too big. Please select file upto 15MB"));
                this.reset_file();
                return;
            }
            this.$('.alert-warning').remove();
            var BinaryReader = new FileReader();
            // file read as DataURL
            BinaryReader.readAsDataURL(file);
            BinaryReader.onloadend = function (upload) {
                var buffer = upload.target.result;
                if (is_image) {
                    self.$("#slide-image").attr("src", buffer);
                }
                buffer = buffer.split(',')[1];
                self.file.data = buffer;
            };

            if (file.type === 'application/pdf') {
                var ArrayReader = new FileReader();
                this.$('.save').button('loading');
                // file read as ArrayBuffer for PDFJS get_Document API
                ArrayReader.readAsArrayBuffer(file);
                ArrayReader.onload = function (evt) {
                    var buffer = evt.target.result;
                    var passwordNeeded = function () {
                        self.display_alert(_t("You can not upload password protected file."));
                        self.reset_file();
                        self.$('.save').button('reset');
                    };
                    PDFJS.getDocument(new Uint8Array(buffer), null, passwordNeeded).then(function getPdf(pdf) {
                        pdf.getPage(1).then(function getFirstPage(page) {
                            var scale = 1;
                            var viewport = page.getViewport(scale);
                            var canvas = document.getElementById('data_canvas');
                            var context = canvas.getContext('2d');
                            canvas.height = viewport.height;
                            canvas.width = viewport.width;
                            // Render PDF page into canvas context
                            page.render({
                                canvasContext: context,
                                viewport: viewport
                            }).then(function () {
                                var image_data = self.$('#data_canvas')[0].toDataURL();
                                self.$("#slide-image").attr("src", image_data);
                                if (loaded) {
                                    self.$('.save').button('reset');
                                }
                                loaded = true;

                            });
                        });
                        var maxPages = pdf.pdfInfo.numPages;
                        var page, j;
                        self.index_content = "";
                        for (j = 1; j <= maxPages; j += 1) {
                            page = pdf.getPage(j);
                            page.then(function (page_obj) {
                                var page_number = page_obj.pageIndex + 1;
                                page_obj.getTextContent().then(function (data) {
                                    var page_content = '';
                                    _.each(data.items, function (obj) {
                                        page_content = page_content + obj.str + " ";
                                    });
                                    self.index_content = self.index_content + page_number + ". " + page_content + '\n';
                                    if (maxPages === page_number) {
                                        if (loaded) {
                                            self.$('.save').button('reset');
                                        }
                                        loaded = true;
                                    }
                                });
                            });
                        }
                    });
                };
            }

            var input = file.name;
            var input_val = input.substr(0, input.lastIndexOf('.')) || input;
            this.check_unique_slide(input_val).then(function (exist) {
                if (exist) {
                    var message = _t("Channel contains the given title, please change before Save or Publish.");
                    self.display_alert(message);
                }
                self.$('#name').val(input_val);
            });
        },
        reset_file: function () {
            var control = this.$('#upload');
            control.replaceWith(control = control.clone(true));
            this.file.name = false;
        },
        display_alert: function (message) {
            this.$('.alert-warning').remove();
            $('
' + message + '
').insertBefore(this.$('form'));
        },

        /**
            Wrapper for select2 load data from server at once and store it.

            @param {String} Placeholder for element.
            @param {bool}  true for multiple selection box, false for single selection
            @param {Function} Function to fetch data from remote location should return $.deferred object
            resolved data should be array of object with id and name. eg. [{'id': id, 'name': 'text'}, ...]
            @returns {Object} select2 wrapper object
        */
        select2_wrapper: function (tag, multi, fetch_fnc) {
            return {
                width: '100%',
                placeholder: tag,
                allowClear: true,
                formatNoMatches: _.str.sprintf(_t("No matches found. Type to create new %s"), tag),
                multiple: multi,
                selection_data: false,
                fetch_rpc_fnc : fetch_fnc,
                formatSelection: function (data) {
                    if (data.tag) {
                        data.text = data.tag;
                    }
                    return data.text;
                },
                createSearchChoice: function (term) {
                    return {
                        id: _.uniqueId('tag_'),
                        create: true,
                        tag: term,
                        text: _.str.sprintf(_t("Create New %s '%s'"), tag, term)
                    };
                },
                fill_data: function (query, data) {
                    var that = this,
                        tags = {results: []};
                    _.each(data, function (obj) {
                        if (that.matcher(query.term, obj.name)) {
                            tags.results.push({id: obj.id, text: obj.name });
                        }
                    });
                    query.callback(tags);
                },
                query: function (query) {
                    var that = this;
                    // fetch data only once and store it
                    if (!this.selection_data) {
                        this.fetch_rpc_fnc().then(function (data) {
                            that.fill_data(query, data);
                            that.selection_data = data;
                        });
                    } else {
                        this.fill_data(query, this.selection_data);
                    }
                }
            };
        },
        // Category management from select2
        set_category_id: function () {
            var self =  this;
            $('#category_id').select2(this.select2_wrapper(_t('Category'), false,
                function () {
                    return openerp.jsonRpc("/web/dataset/call_kw", 'call', {
                        model: 'slide.category',
                        method: 'search_read',
                        args: [],
                        kwargs: {
                            fields: ['name'],
                            domain: [['channel_id', '=', self.channel_id]],
                            context: website.get_context()
                        }
                    });
                }));
        },
        get_category_id: function () {
            var value = $('#category_id').select2('data');
            if (value && value.create) {
                return [0, {'name': value.text}];
            }
            return [value ? value.id : null];
        },
        // Tags management from select2
        set_tag_ids: function () {
            $('#tag_ids').select2(this.select2_wrapper(_t('Tags'), true, function () {
                return openerp.jsonRpc("/web/dataset/call_kw", 'call', {
                    model: 'slide.tag',
                    method: 'search_read',
                    args: [],
                    kwargs: {
                        fields: ['name'],
                        context: website.get_context()
                    }
                });
            }));
        },
        get_tag_ids: function () {
            var res = [];
            _.each($('#tag_ids').select2('data'),
                function (val) {
                    if (val.create) {
                        res.push([0, 0, {'name': val.text}]);
                    } else {
                        res.push([4, val.id]);
                    }
                });
            return res;
        },
        // Values and save
        get_value: function () {
            var canvas = this.$('#data_canvas')[0],
                values = {
                    'channel_id': this.channel_id || '',
                    'name': this.$('#name').val(),
                    'url': this.$('#url').val(),
                    'description': this.$('#description').val(),
                    'tag_ids': this.get_tag_ids(),
                    'category_id': this.get_category_id()
                };
            if (this.file.type === 'application/pdf') {
                _.extend(values, {
                    'image': canvas.toDataURL().split(',')[1],
                    'index_content': this.index_content,
                    'slide_type': canvas.height > canvas.width ? 'document' : 'presentation',
                    'mime_type': this.file.type,
                    'datas': this.file.data
                });
            }
            if (/^image\/.*/.test(this.file.type)) {
                _.extend(values, {
                    'slide_type': 'infographic',
                    'mime_type': this.file.type,
                    'datas': this.file.data
                });
            }
            return values;
        },
        validate: function () {
            this.$('.form-group').removeClass('has-error');
            if (!this.$('#name').val()) {
                this.$('#name').closest('.form-group').addClass('has-error');
                return false;
            }
            var url = this.$('#url').val() ? this.is_valid_url : false;
            if (!(this.file.name || url)) {
                this.$('#url').closest('.form-group').addClass('has-error');
                return false;
            }
            return true;
        },
        save: function (ev) {
            var self = this;
            if (this.validate()) {
                var values = this.get_value();
                if ($(ev.target).data('published')) {
                    values.website_published = true;
                }
                this.$('.oe_slides_upload_loading').show();
                this.$('.modal-footer, .modal-body').hide();
                openerp.jsonRpc("/slides/add_slide", 'call', values).then(function (data) {
                    if (data.error) {
                        self.display_alert(data.error);
                        self.$('.oe_slides_upload_loading').hide();
                        self.$('.modal-footer, .modal-body').show();

                    } else {
                        window.location = data.url;
                    }
                });
            }
        },
        cancel: function () {
            this.trigger("cancel");
        }
    });

    // bind the event to the button
    $('.oe_slide_js_upload').on('click', function () {
        var channel_id = $(this).attr('channel_id');
        website.slide.page_widgets['upload_dialog'] = new website.slide.Dialog(this, channel_id).appendTo(document.body);
    });

});<commit_msg>[FIX] website_forum: wrapped sharing js inside if_dom_contains<commit_after>/*global $, openerp, _, PDFJS */
$(document).ready(function () {
    "use strict";

    openerp.website.if_dom_contains('.oe_slide_js_upload', function () {

        var website = openerp.website;
        var _t = openerp._t;

        website.slide.template = website.add_template_file('/website_slides/static/src/xml/website_slides.xml');

        website.slide.Dialog = openerp.Widget.extend({
            template: 'website.slide.upload',
            events: {
                'hidden.bs.modal': 'destroy',
                'click button.save': 'save',
                'click button[data-dismiss="modal"]': 'cancel',
                'change input#upload': 'slide_upload',
                'change input#url': 'slide_url',
                'click .list-group-item': function (ev) {
                    this.$('.list-group-item').removeClass('active');
                    $(ev.target).closest('li').addClass('active');
                }
            },
            init: function (el, channel_id) {
                this._super(el, channel_id);
                this.channel_id = parseInt(channel_id, 10);
                this.file = {};
                this.index_content = "";
            },
            start: function () {
                this.$el.modal({
                    backdrop: 'static'
                });
                this.set_category_id();
                this.set_tag_ids();
            },
            slide_url: function (ev) {
                var self = this,
                    value = {
                        'url': $(ev.target).val(),
                        'channel_id': self.channel_id
                    };
                this.$('.alert-warning').remove();
                this.is_valid_url = false;
                this.$('.save').button('loading');
                openerp.jsonRpc('/slides/dialog_preview/', 'call', value).then(function (data) {
                    self.$('.save').button('reset');
                    if (data.error) {
                        self.display_alert(data.error);
                    } else {
                        self.$("#slide-image").attr("src", data.url_src);
                        self.$('#name').val(data.title);
                        self.$('#description').val(data.description);
                        self.is_valid_url = true;
                    }
                });
            },
            check_unique_slide: function (file_name) {
                var self = this;
                return openerp.jsonRpc('/web/dataset/call_kw', 'call', {
                    model: 'slide.slide',
                    method: 'search_count',
                    args: [[['channel_id', '=', self.channel_id], ['name', '=', file_name]]],
                    kwargs: {}
                });
            },
            slide_upload: function (ev) {
                var self = this,
                    file = ev.target.files[0],
                    is_image = /^image\/.*/.test(file.type),
                    loaded = false;
                this.file.name = file.name;
                this.file.type = file.type;
                if (!(is_image || this.file.type === 'application/pdf')) {
                    this.display_alert(_t("Invalid file type. Please select pdf or image file"));
                    this.reset_file();
                    return;
                }
                if (file.size / 1024 / 1024 > 15) {
                    this.display_alert(_t("File is too big. Please select file upto 15MB"));
                    this.reset_file();
                    return;
                }
                this.$('.alert-warning').remove();
                var BinaryReader = new FileReader();
                // file read as DataURL
                BinaryReader.readAsDataURL(file);
                BinaryReader.onloadend = function (upload) {
                    var buffer = upload.target.result;
                    if (is_image) {
                        self.$("#slide-image").attr("src", buffer);
                    }
                    buffer = buffer.split(',')[1];
                    self.file.data = buffer;
                };

                if (file.type === 'application/pdf') {
                    var ArrayReader = new FileReader();
                    this.$('.save').button('loading');
                    // file read as ArrayBuffer for PDFJS get_Document API
                    ArrayReader.readAsArrayBuffer(file);
                    ArrayReader.onload = function (evt) {
                        var buffer = evt.target.result;
                        var passwordNeeded = function () {
                            self.display_alert(_t("You can not upload password protected file."));
                            self.reset_file();
                            self.$('.save').button('reset');
                        };
                        PDFJS.getDocument(new Uint8Array(buffer), null, passwordNeeded).then(function getPdf(pdf) {
                            pdf.getPage(1).then(function getFirstPage(page) {
                                var scale = 1;
                                var viewport = page.getViewport(scale);
                                var canvas = document.getElementById('data_canvas');
                                var context = canvas.getContext('2d');
                                canvas.height = viewport.height;
                                canvas.width = viewport.width;
                                // Render PDF page into canvas context
                                page.render({
                                    canvasContext: context,
                                    viewport: viewport
                                }).then(function () {
                                    var image_data = self.$('#data_canvas')[0].toDataURL();
                                    self.$("#slide-image").attr("src", image_data);
                                    if (loaded) {
                                        self.$('.save').button('reset');
                                    }
                                    loaded = true;

                                });
                            });
                            var maxPages = pdf.pdfInfo.numPages;
                            var page, j;
                            self.index_content = "";
                            for (j = 1; j <= maxPages; j += 1) {
                                page = pdf.getPage(j);
                                page.then(function (page_obj) {
                                    var page_number = page_obj.pageIndex + 1;
                                    page_obj.getTextContent().then(function (data) {
                                        var page_content = '';
                                        _.each(data.items, function (obj) {
                                            page_content = page_content + obj.str + " ";
                                        });
                                        self.index_content = self.index_content + page_number + ". " + page_content + '\n';
                                        if (maxPages === page_number) {
                                            if (loaded) {
                                                self.$('.save').button('reset');
                                            }
                                            loaded = true;
                                        }
                                    });
                                });
                            }
                        });
                    };
                }

                var input = file.name;
                var input_val = input.substr(0, input.lastIndexOf('.')) || input;
                this.check_unique_slide(input_val).then(function (exist) {
                    if (exist) {
                        var message = _t("Channel contains the given title, please change before Save or Publish.");
                        self.display_alert(message);
                    }
                    self.$('#name').val(input_val);
                });
            },
            reset_file: function () {
                var control = this.$('#upload');
                control.replaceWith(control = control.clone(true));
                this.file.name = false;
            },
            display_alert: function (message) {
                this.$('.alert-warning').remove();
                $('
' + message + '
').insertBefore(this.$('form'));
            },

            /**
                Wrapper for select2 load data from server at once and store it.

                @param {String} Placeholder for element.
                @param {bool}  true for multiple selection box, false for single selection
                @param {Function} Function to fetch data from remote location should return $.deferred object
                resolved data should be array of object with id and name. eg. [{'id': id, 'name': 'text'}, ...]
                @returns {Object} select2 wrapper object
            */
            select2_wrapper: function (tag, multi, fetch_fnc) {
                return {
                    width: '100%',
                    placeholder: tag,
                    allowClear: true,
                    formatNoMatches: _.str.sprintf(_t("No matches found. Type to create new %s"), tag),
                    multiple: multi,
                    selection_data: false,
                    fetch_rpc_fnc : fetch_fnc,
                    formatSelection: function (data) {
                        if (data.tag) {
                            data.text = data.tag;
                        }
                        return data.text;
                    },
                    createSearchChoice: function (term) {
                        return {
                            id: _.uniqueId('tag_'),
                            create: true,
                            tag: term,
                            text: _.str.sprintf(_t("Create New %s '%s'"), tag, term)
                        };
                    },
                    fill_data: function (query, data) {
                        var that = this,
                            tags = {results: []};
                        _.each(data, function (obj) {
                            if (that.matcher(query.term, obj.name)) {
                                tags.results.push({id: obj.id, text: obj.name });
                            }
                        });
                        query.callback(tags);
                    },
                    query: function (query) {
                        var that = this;
                        // fetch data only once and store it
                        if (!this.selection_data) {
                            this.fetch_rpc_fnc().then(function (data) {
                                that.fill_data(query, data);
                                that.selection_data = data;
                            });
                        } else {
                            this.fill_data(query, this.selection_data);
                        }
                    }
                };
            },
            // Category management from select2
            set_category_id: function () {
                var self =  this;
                $('#category_id').select2(this.select2_wrapper(_t('Category'), false,
                    function () {
                        return openerp.jsonRpc("/web/dataset/call_kw", 'call', {
                            model: 'slide.category',
                            method: 'search_read',
                            args: [],
                            kwargs: {
                                fields: ['name'],
                                domain: [['channel_id', '=', self.channel_id]],
                                context: website.get_context()
                            }
                        });
                    }));
            },
            get_category_id: function () {
                var value = $('#category_id').select2('data');
                if (value && value.create) {
                    return [0, {'name': value.text}];
                }
                return [value ? value.id : null];
            },
            // Tags management from select2
            set_tag_ids: function () {
                $('#tag_ids').select2(this.select2_wrapper(_t('Tags'), true, function () {
                    return openerp.jsonRpc("/web/dataset/call_kw", 'call', {
                        model: 'slide.tag',
                        method: 'search_read',
                        args: [],
                        kwargs: {
                            fields: ['name'],
                            context: website.get_context()
                        }
                    });
                }));
            },
            get_tag_ids: function () {
                var res = [];
                _.each($('#tag_ids').select2('data'),
                    function (val) {
                        if (val.create) {
                            res.push([0, 0, {'name': val.text}]);
                        } else {
                            res.push([4, val.id]);
                        }
                    });
                return res;
            },
            // Values and save
            get_value: function () {
                var canvas = this.$('#data_canvas')[0],
                    values = {
                        'channel_id': this.channel_id || '',
                        'name': this.$('#name').val(),
                        'url': this.$('#url').val(),
                        'description': this.$('#description').val(),
                        'tag_ids': this.get_tag_ids(),
                        'category_id': this.get_category_id()
                    };
                if (this.file.type === 'application/pdf') {
                    _.extend(values, {
                        'image': canvas.toDataURL().split(',')[1],
                        'index_content': this.index_content,
                        'slide_type': canvas.height > canvas.width ? 'document' : 'presentation',
                        'mime_type': this.file.type,
                        'datas': this.file.data
                    });
                }
                if (/^image\/.*/.test(this.file.type)) {
                    _.extend(values, {
                        'slide_type': 'infographic',
                        'mime_type': this.file.type,
                        'datas': this.file.data
                    });
                }
                return values;
            },
            validate: function () {
                this.$('.form-group').removeClass('has-error');
                if (!this.$('#name').val()) {
                    this.$('#name').closest('.form-group').addClass('has-error');
                    return false;
                }
                var url = this.$('#url').val() ? this.is_valid_url : false;
                if (!(this.file.name || url)) {
                    this.$('#url').closest('.form-group').addClass('has-error');
                    return false;
                }
                return true;
            },
            save: function (ev) {
                var self = this;
                if (this.validate()) {
                    var values = this.get_value();
                    if ($(ev.target).data('published')) {
                        values.website_published = true;
                    }
                    this.$('.oe_slides_upload_loading').show();
                    this.$('.modal-footer, .modal-body').hide();
                    openerp.jsonRpc("/slides/add_slide", 'call', values).then(function (data) {
                        if (data.error) {
                            self.display_alert(data.error);
                            self.$('.oe_slides_upload_loading').hide();
                            self.$('.modal-footer, .modal-body').show();

                        } else {
                            window.location = data.url;
                        }
                    });
                }
            },
            cancel: function () {
                this.trigger("cancel");
            }
        });

        // bind the event to the button
        $('.oe_slide_js_upload').on('click', function () {
            var channel_id = $(this).attr('channel_id');
            website.slide.page_widgets['upload_dialog'] = new website.slide.Dialog(this, channel_id).appendTo(document.body);
        });
    });
});<|endoftext|>


<commit_before>import Ember from 'ember';
import needSaveCurrentAgregator from '../utils/need-save-current-agregator';

/**
  Mixin for {{#crossLink "DS.Route"}}Route{{/crossLink}}
  to support work with {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

  @class FlexberryGroupeditRouteMixin
  @extends Ember.Mixin
  @public
*/
export default Ember.Mixin.create({
  /**
    Service that triggers {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.

    @private
    @property _groupEditEventsService
    @readOnly
    @type Service
    @default ObjectlistviewEventsService
  */
  _groupEditEventsService: Ember.inject.service('objectlistview-events'),

  /**
    Service that lets interact between agregator's and detail's form.

    @property flexberryDetailInteractionService
    @readOnly
    @type Service
    @default DetailInteractionService
  */
  flexberryDetailInteractionService: Ember.inject.service('detail-interaction'),

  actions: {
    /**
      {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} row click handler.
      It sets `modelNoRollBack` to `true` at current controller, redirects to detail's route, save necessary data to service.

      @method actions.groupEditRowClick
      @param {Ember.Object} record Record related to clicked table row.
      @param {Object} [options] Record related to clicked table row.
      @param {Boolean} options.saveBeforeRouteLeave Flag: indicates whether to save current model before going to the detail's route.
      @param {Boolean} options.editOnSeparateRoute Flag: indicates whether to edit detail on separate route.
      @param {String} options.modelName Clicked detail model name (used to create record if record is undefined).
      @param {Array} options.detailArray Current detail array (used to add record to if record is undefined).
      @param {Boolean} options.editFormRoute Path to detail's form.
    */
    groupEditRowClick(record, options) {
      let methodOptions = {
        saveBeforeRouteLeave: false,
        editOnSeparateRoute: false,
        modelName: undefined,
        detailArray: undefined,
        editFormRoute: undefined,
        readonly: false
      };
      methodOptions = Ember.merge(methodOptions, options);
      let editOnSeparateRoute = methodOptions.editOnSeparateRoute;
      let saveBeforeRouteLeave = methodOptions.saveBeforeRouteLeave;

      if (!editOnSeparateRoute) {
        return;
      }

      let _this = this;
      let editFormRoute = methodOptions.editFormRoute;
      if (!editFormRoute) {
        throw new Error('Detail\'s edit form route is undefined.');
      }

      let goToOtherRouteFunction = function() {
        if (!record)
        {
          let modelName = methodOptions.modelName;
          if (!modelName) {
            throw new Error('Detail\'s model name is undefined.');
          }

          let detailArray = methodOptions.detailArray;
          var modelToAdd = _this.store.createRecord(modelName, {});
          detailArray.addObject(modelToAdd);
          record = modelToAdd;
        }

        _this.controller.set('modelNoRollBack', true);

        let flexberryDetailInteractionService = _this.get('flexberryDetailInteractionService');
        flexberryDetailInteractionService.pushValue(
          'modelCurrentAgregatorPathes', _this.controller.get('modelCurrentAgregatorPathes'), _this.get('router.url'));
        flexberryDetailInteractionService.set('modelSelectedDetail', record);
        flexberryDetailInteractionService.set('saveBeforeRouteLeave', saveBeforeRouteLeave);
        flexberryDetailInteractionService.pushValue(
          'modelCurrentAgregators', _this.controller.get('modelCurrentAgregators'), _this.controller.get('model'));

        if (record.get('isNew')) {
          let newModelPath = _this.newRoutePath(editFormRoute);
          _this.transitionTo(newModelPath).then((newRoute) => {
            newRoute.controller.set('readonly', methodOptions.readonly);
          });
        } else {
          _this.transitionTo(editFormRoute, record.get('id')).then((newRoute) => {
            newRoute.controller.set('readonly', methodOptions.readonly);
          });
        }
      };

      if (saveBeforeRouteLeave) {
        let model = this.controller.get('model');
        if (!Ember.$.isEmptyObject(model.changedAttributes()) || !Ember.$.isEmptyObject(model.changedBelongsTo())) {
          this.controller.save(false, true).then(() => {
            goToOtherRouteFunction();
          }).catch((errorData) => {
            this.controller.rejectError(errorData, this.get('i18n').t('forms.edit-form.save-failed-message'));
          });
        } else {
          goToOtherRouteFunction();
        }
      } else {
        goToOtherRouteFunction();
      }
    },

    saveAgregator(agregatorModel) {
      let agregator = agregatorModel ? agregatorModel : this.get('controller.model');
      if (needSaveCurrentAgregator.call(this, agregator)) {
        agregator.save();
      }
    }
  },

  /**
    This hook is executed when the router enters the route. It is not executed when the model for the route changes.

    It is used to subscribe on {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.

    @method activate
  */
  activate() {
    this._super(...arguments);

    this.get('_groupEditEventsService').on('olvRowAdded', this, this._rowAdded);
    this.get('_groupEditEventsService').on('olvRowDeleted', this, this._rowDeleted);
    this.get('_groupEditEventsService').on('olvRowsChanged', this, this._rowChanged);
  },

  /**
    This hook is executed when the router completely exits this route. It is not executed when the model for the route changes.

    It is used to unsubscribe from {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.

    @method deactivate
  */
  deactivate() {
    this._super(...arguments);

    this.get('_groupEditEventsService').off('olvRowAdded', this, this._rowAdded);
    this.get('_groupEditEventsService').off('olvRowDeleted', this, this._rowDeleted);
    this.get('_groupEditEventsService').off('olvRowsChanged', this, this._rowChanged);
  },

  /**
    It forms path for new model's route.

    @method newRoutePath
    @param {String} ordinalPath The path to model's route.
    @return {String} The path to new model's route.
  */
  newRoutePath(ordinalPath) {
    return ordinalPath + '.new';
  },

  /**
    Event handler for "row has been selected" event in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

    @method _rowAdded
    @private

    @param {String} componentName The name of {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
    @param {DS.Model} record The model corresponding to added row in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
  */
  _rowAdded(componentName, record) {
    // Manually make record dirty, because ember-data does not do it when relationship changes.
    this.controller.get('model').makeDirty();
  },

  /**
    Event handler for "row has been deleted" event in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

    @method _rowDeleted
    @private

    @param {String} componentName The name of {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
    @param {DS.Model} record The model corresponding to deleted row in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
  */
  _rowDeleted(componentName, record) {
    // Manually make record dirty, because ember-data does not do it when relationship changes.
    this.controller.get('model').makeDirty();
  },

  /**
    Event handler for "model(s) corresponding to some row(s) was changed" event in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

    @method _rowChanged
    @private

    @param {String} componentName The name of {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
  */
  _rowChanged(componentName) {
    // Manually make record dirty, because ember-data does not do it when relationship changes.
    this.controller.get('model').makeDirty();
  }
});
<commit_msg>Add checking of `isNew` state of model<commit_after>import Ember from 'ember';
import needSaveCurrentAgregator from '../utils/need-save-current-agregator';

/**
  Mixin for {{#crossLink "DS.Route"}}Route{{/crossLink}}
  to support work with {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

  @class FlexberryGroupeditRouteMixin
  @extends Ember.Mixin
  @public
*/
export default Ember.Mixin.create({
  /**
    Service that triggers {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.

    @private
    @property _groupEditEventsService
    @readOnly
    @type Service
    @default ObjectlistviewEventsService
  */
  _groupEditEventsService: Ember.inject.service('objectlistview-events'),

  /**
    Service that lets interact between agregator's and detail's form.

    @property flexberryDetailInteractionService
    @readOnly
    @type Service
    @default DetailInteractionService
  */
  flexberryDetailInteractionService: Ember.inject.service('detail-interaction'),

  actions: {
    /**
      {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} row click handler.
      It sets `modelNoRollBack` to `true` at current controller, redirects to detail's route, save necessary data to service.

      @method actions.groupEditRowClick
      @param {Ember.Object} record Record related to clicked table row.
      @param {Object} [options] Record related to clicked table row.
      @param {Boolean} options.saveBeforeRouteLeave Flag: indicates whether to save current model before going to the detail's route.
      @param {Boolean} options.editOnSeparateRoute Flag: indicates whether to edit detail on separate route.
      @param {String} options.modelName Clicked detail model name (used to create record if record is undefined).
      @param {Array} options.detailArray Current detail array (used to add record to if record is undefined).
      @param {Boolean} options.editFormRoute Path to detail's form.
    */
    groupEditRowClick(record, options) {
      let methodOptions = {
        saveBeforeRouteLeave: false,
        editOnSeparateRoute: false,
        modelName: undefined,
        detailArray: undefined,
        editFormRoute: undefined,
        readonly: false
      };
      methodOptions = Ember.merge(methodOptions, options);
      let editOnSeparateRoute = methodOptions.editOnSeparateRoute;
      let saveBeforeRouteLeave = methodOptions.saveBeforeRouteLeave;

      if (!editOnSeparateRoute) {
        return;
      }

      let _this = this;
      let editFormRoute = methodOptions.editFormRoute;
      if (!editFormRoute) {
        throw new Error('Detail\'s edit form route is undefined.');
      }

      let goToOtherRouteFunction = function() {
        if (!record)
        {
          let modelName = methodOptions.modelName;
          if (!modelName) {
            throw new Error('Detail\'s model name is undefined.');
          }

          let detailArray = methodOptions.detailArray;
          var modelToAdd = _this.store.createRecord(modelName, {});
          detailArray.addObject(modelToAdd);
          record = modelToAdd;
        }

        _this.controller.set('modelNoRollBack', true);

        let flexberryDetailInteractionService = _this.get('flexberryDetailInteractionService');
        flexberryDetailInteractionService.pushValue(
          'modelCurrentAgregatorPathes', _this.controller.get('modelCurrentAgregatorPathes'), _this.get('router.url'));
        flexberryDetailInteractionService.set('modelSelectedDetail', record);
        flexberryDetailInteractionService.set('saveBeforeRouteLeave', saveBeforeRouteLeave);
        flexberryDetailInteractionService.pushValue(
          'modelCurrentAgregators', _this.controller.get('modelCurrentAgregators'), _this.controller.get('model'));

        if (record.get('isNew')) {
          let newModelPath = _this.newRoutePath(editFormRoute);
          _this.transitionTo(newModelPath).then((newRoute) => {
            newRoute.controller.set('readonly', methodOptions.readonly);
          });
        } else {
          _this.transitionTo(editFormRoute, record.get('id')).then((newRoute) => {
            newRoute.controller.set('readonly', methodOptions.readonly);
          });
        }
      };

      if (saveBeforeRouteLeave) {
        let model = this.controller.get('model');
        let isModelChanged = !Ember.$.isEmptyObject(model.changedAttributes()) || !Ember.$.isEmptyObject(model.changedBelongsTo());
        let isModelNew = model.get('isNew');
        if (isModelNew || isModelChanged) {
          this.controller.save(false, true).then(() => {
            goToOtherRouteFunction();
          }).catch((errorData) => {
            this.controller.rejectError(errorData, this.get('i18n').t('forms.edit-form.save-failed-message'));
          });
        } else {
          goToOtherRouteFunction();
        }
      } else {
        goToOtherRouteFunction();
      }
    },

    saveAgregator(agregatorModel) {
      let agregator = agregatorModel ? agregatorModel : this.get('controller.model');
      if (needSaveCurrentAgregator.call(this, agregator)) {
        agregator.save();
      }
    }
  },

  /**
    This hook is executed when the router enters the route. It is not executed when the model for the route changes.

    It is used to subscribe on {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.

    @method activate
  */
  activate() {
    this._super(...arguments);

    this.get('_groupEditEventsService').on('olvRowAdded', this, this._rowAdded);
    this.get('_groupEditEventsService').on('olvRowDeleted', this, this._rowDeleted);
    this.get('_groupEditEventsService').on('olvRowsChanged', this, this._rowChanged);
  },

  /**
    This hook is executed when the router completely exits this route. It is not executed when the model for the route changes.

    It is used to unsubscribe from {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}} events.

    @method deactivate
  */
  deactivate() {
    this._super(...arguments);

    this.get('_groupEditEventsService').off('olvRowAdded', this, this._rowAdded);
    this.get('_groupEditEventsService').off('olvRowDeleted', this, this._rowDeleted);
    this.get('_groupEditEventsService').off('olvRowsChanged', this, this._rowChanged);
  },

  /**
    It forms path for new model's route.

    @method newRoutePath
    @param {String} ordinalPath The path to model's route.
    @return {String} The path to new model's route.
  */
  newRoutePath(ordinalPath) {
    return ordinalPath + '.new';
  },

  /**
    Event handler for "row has been selected" event in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

    @method _rowAdded
    @private

    @param {String} componentName The name of {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
    @param {DS.Model} record The model corresponding to added row in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
  */
  _rowAdded(componentName, record) {
    // Manually make record dirty, because ember-data does not do it when relationship changes.
    this.controller.get('model').makeDirty();
  },

  /**
    Event handler for "row has been deleted" event in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

    @method _rowDeleted
    @private

    @param {String} componentName The name of {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
    @param {DS.Model} record The model corresponding to deleted row in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
  */
  _rowDeleted(componentName, record) {
    // Manually make record dirty, because ember-data does not do it when relationship changes.
    this.controller.get('model').makeDirty();
  },

  /**
    Event handler for "model(s) corresponding to some row(s) was changed" event in {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.

    @method _rowChanged
    @private

    @param {String} componentName The name of {{#crossLink "FlexberryGroupeditComponent"}}{{/crossLink}}.
  */
  _rowChanged(componentName) {
    // Manually make record dirty, because ember-data does not do it when relationship changes.
    this.controller.get('model').makeDirty();
  }
});
<|endoftext|>


<commit_before>var Manager = function(){
	var Manager = this;
	Manager.path = {
		handler: '/app/handlers/manager.php'
	};
	Manager.init();
};

// Initiate template manager
Manager.prototype.init = function() {
	var Manager = this;

	getComponents(function(){
		tempalteList()
	})

	function getComponents(callback){
		$.getJSON(Manager.path.handler, {
			action: 'getComponents'
		}, function(components) {
			Manager.components = components
			if ( typeof callback == 'function' ) {
				callback();
			}
		});
	}

	function tempalteList(callback){
		$.getJSON(Manager.path.handler,{
			action: 'list'
		}, function(templateList){
			Manager.list = templateList;
			Manager.renderList('active-list');
			Manager.bindEvents()
		});
	}
};
Manager.prototype.bindEvents = function() {
	var Manager = this;
	// loop through events
	_.each(Manager.events, function (eventFunction, eventKey) {
		// seperate multiple selectors
		selectorArray = eventKey.split(' ');

		_.each(selectorArray, function(selectorValue, selectorIndex){
			$(document).on('click', '[data-manager ="' + selectorValue + '"]', function(e){
				e.preventDefault();
				eventFunction(Manager, $(this));
			})
		})
	})
};

Manager.prototype.events = {
	// INSTALL / UNINSTALL TABLE
	installer: function(managerRef, target){
		return;
		var Manager = managerRef;
		var target = $(target);
		$.post(Manager.path.handler, {
			//function type install : uninstall
			action: target.val().toLowerCase()
		}, function (response){

			if ( response.success === true ) {
				$('.listItem').remove();
				Manager.list = {};
			}

			target.parent('.manager-installer').find('.feedback').html(response.message);
		}, 'json');//post end
	},

	// CREATE NEW TEMPALTE
	create: function(managerRef, target){
		var Manager = managerRef;
		var target = $(target);

		modalHelper({
			modal: Manager.components['bootstrap-modal'].contents,
			view: Manager.components['manager-template-action'].contents,
			data:{
				action: 'Create Template'
			},
			title: 'Create New Template',
			shown: function(event, modal){

				$(modal).find('.templateAction').on('click.createTemplate', function(){

					if( $(modal).find('.templateName').val() == '' ){

						$(modal).find('.form-group').addClass('has-error');
						$(modal).find('.response').html('No Template Name Provided');
					} else {

						$.post(Manager.path.handler, {
							action: 'new',
							// template title
							templateName : $(modal).find('.templateName').val()
						}, function(response){
							if ( response.success === true) {
								$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
								$(modal).find('.response').html('')

								// add to template list
								Manager.list[response.ID] = {
									ID: response.ID,
									title: response.title,
									version:response.version,
									active: response.active
								};

								//render template
								Manager.renderList('active-list');

								setTimeout(function(){
									$(modal).modal('hide');
								}, 500)

							} else {
								$(modal).find('.form-group').addClass('has-error');
								// parse response
								var errMsg = objectToText(response.message);

								// append response
								$(modal).find('.response').html(errMsg)
							}
						}, 'json');// post end
					}
				});
			}
		});
	},

	update: function(managerRef, target){
		var Manager = managerRef;
		var target = $(target);

		// template node
		var template = target.parents('[data-template-id]');
		// tempalte id
		var templateID = template.data('template-id');
		// Manager.list instance
		var templateInfo = Manager.list[templateID];

		modalHelper({
			modal: Manager.components['bootstrap-modal'].contents,
			view: Manager.components['manager-template-action'].contents,
			data:{
				action: 'Update template'
			},
			title: 'Update template',
			show: function(event, modal){
				$(modal).find('.templateName').val(templateInfo.title);
			},
			shown: function(event, modal){
				$(modal).find('.templateAction').on('click.updateTemplate', function(){
					var newTitle = $(modal).find('.templateName').val();

					// return if prompt is empty or canceled
					if ( newTitle === '' ) {

						$(modal).find('.form-group').addClass('has-error');
						$(modal).find('.response').html('No Title Provided.')
					} else {

						$.post(Manager.path.handler, {
							action: 'update',
							// template id
							templateID: templateID,
							//new template name
							newName: newTitle
						}, function(response){

							if ( response.success === true ) {
								$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
								$(modal).find('.response').html('')

								// replace title
								template.find('.template-title-link').html(newTitle);

								setTimeout(function(){
									$(modal).modal('hide');
								}, 500)
							} else {
								$(modal).find('.form-group').addClass('has-error');
								$(modal).find('.response').html(response.message)
							}
						}, 'json');//post end
					}// else
				}); //click.updateTemplate
			} //shown
		});// modelHelper
	},

	clone: function(managerRef, target){
		var Manager = managerRef;
		var target = $(target);

		modalHelper({
			modal: Manager.components['bootstrap-modal'].contents,
			view: Manager.components['manager-template-action'].contents,
			data:{
				action: 'Template Name'
			},
			title: 'Clone Template',
			shown: function(event, modal){
				$(modal).find('.templateAction').on('click.cloneTemplate', function(){
					var newTitle = $(modal).find('.templateName').val();

					// return if prompt is empty or canceled
					if ( newTitle === '' ) {

						$(modal).find('.form-group').addClass('has-error');
						$(modal).find('.response').html('No Title Provided for New Template.')
					} else {

						$.post(Manager.path.handler, {
							action: 'clone',
							//template to be cloned ID
							cloneID: target.parents('[data-template-id]').data('template-id'),
							// new template name
							newTempName: $(modal).find('.templateName').val()
						}, function(response){
							if ( response.success === true ) {
								$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
								$(modal).find('.response').html('')

								// add to template list
								Manager.list[response.ID] = {
									ID: response.ID,
									title: response.title,
									version:response.version.toString(),
									active: response.active
								};
								//render template
								Manager.renderList('active-list');
								setTimeout(function(){
									$(modal).modal('hide');
								}, 500);
							} else {
								$(modal).find('.form-group').addClass('has-error');
								// parse response
								var errMsg = objectToText(response.message);

								// append response
								$(modal).find('.response').html(errMsg)
							}
						}, 'json');//post end
					}// else
				}); //click.cloneTemplate
			} //shown
		});// modelHelper
	},

	'trash delete': function(managerRef, target){
		var Manager = managerRef
		var target = $(target);
		// template node
		var template = target.parents('[data-template-id]');
		// template id
		var templateID = template.data('template-id');
		// Manager.list instance
		var templateInfo = Manager.list[templateID];

		modalHelper({
			modal: Manager.components['bootstrap-modal'].contents,
			view: Manager.components['manager-template-delete'].contents,
			data:{
				action: (templateInfo.active)? 'Move To Trash' : 'Permenetly Delete',
				isActive: templateInfo.active
			},
			title: (templateInfo.active)? 'Move To Trash' : 'Permenetly Delete',
			shown: function(event, modal){
				$(modal).find('.templateAction').on('click.delete', function(){
					$.post(Manager.path.handler, {
						action: 'delete',
						// temple id
						templateID: templateID,
						// template status
						isActive: Boolean(templateInfo.active)
					}, function(response){

						if ( response.success === true ) {
							$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
							$(modal).find('.response').html('')

							template.remove();

							if ( templateInfo.active === true ) {
								templateInfo.active = false;
							} else {
								delete Manager.list[templateID];
							}

							setTimeout(function(){
								$(modal).modal('hide');
							}, 500);

						} else {
							// parse error response
							$(modal).find('.form-group').addClass('has-error');
							// parse response
							var errMsg = objectToText(response.message);

							// append response
							$(modal).find('.response').html(errMsg)
						}
					}, 'json');// post
				})
			}
		})

		return

		// alter message if template is active or inactive
		var confirmMsg = ( templateInfo.active === true )? 'Press OK Move ' + templateInfo.title + ' Template to Trash' : 'Press OK to Permenetly Delete  ' + templateInfo.title;
		var delNodeConfirm = window.confirm(confirmMsg);

		// return if confirmation canceled
		if ( delNodeConfirm === false ) {
			return;
		}

		$.post(Manager.path.handler, {
			action: 'delete',
			// temple id
			templateID: templateID,
			// template status
			isActive: Boolean(templateInfo.active)
		}, function(response){

			if ( response.success === true ) {

				template.remove();

				if ( templateInfo.active === true ) {
					templateInfo.active = false;
				} else {
					delete Manager.list[templateID];
				}
			} else {
				window.alert('error deleting template');
			}
		}, 'json');// post
	},

	'preview': function(managerRef, target){
		var Manager = managerRef
		var target = $(target);
		var template = target.parents('[data-template-id]');
		// template id
		var templateID = template.data('template-id');
		// Manager.list instance
		var templateInfo = Manager.list[templateID];
		var previewUrl = [
			'template=' + templateInfo.title,
			'id=' + templateInfo.ID,
			'version=' + templateInfo.version
		]
		window.open('/template/?' + previewUrl.join('&'), '_blank')
	},

	'list-trash list-active': function(managerRef, target){
		var Manager = managerRef
		var listType = target.data('manager');

		// find active tab, remove class active if clicked tab is not active tab
		$('.templatesNavigations').find('.active').not($(target)).removeClass('active');

		$(target).addClass('active');

		// render if not active list
		if( $('[data-manager-list-type=' + listType + ']').size() == 0 ){
			Manager.renderList(listType);
		}
	}
}

Manager.prototype.renderList = function(listType) {
	var Manager = this;
	var getActive = /active/.test(listType);

	var filterTemplates = _.filter(Manager.list, function(listItem) {
		console.log(Manager.list, listItem);
		return listItem.active == getActive;
	});

	filterTemplates.reverse()

	$('.manager-templates').handlebars({
		data:{
			templates: filterTemplates,
			listType: listType
		},
		view: Manager.components['manager-listing'].contents
	})
};<commit_msg>refactor editor event binding<commit_after>var Manager = function(){
	var Manager = this;
	Manager.path = {
		handler: '/app/handlers/manager.php'
	};
	Manager.init();
};

// Initiate template manager
Manager.prototype.init = function() {
	var Manager = this;

	getComponents(function(){
		tempalteList();
	});

	function getComponents(callback){
		$.getJSON(Manager.path.handler, {
			action: 'getComponents'
		}, function(components) {
			Manager.components = components;
			if ( typeof callback == 'function' ) {
				callback();
			}
		});
	}

	function tempalteList(callback){
		$.getJSON(Manager.path.handler,{
			action: 'list'
		}, function(templateList){
			Manager.list = templateList;
			Manager.renderList('active-list');
			Manager.bindEvents();
		});
	}
};
Manager.prototype.bindEvents = function() {
	var Manager = this;
	// loop through events
	_.each(Manager.events, function (eventValue, eventKey) {
		$(document).on(eventValue.eventType, eventValue.selector, function(e){
			e.preventDefault();
			eventValue.action(Manager, $(this));
		});
	});
};

Manager.prototype.events = {
	// INSTALL / UNINSTALL TABLE
	'installer': {
		eventType: 'click.installer',
		selector: '[data-manager=installer]',
		action: function(managerRef, target){
			/*var Manager = managerRef;
			$.post(Manager.path.handler, {
				//function type install : uninstall
				action: target.val().toLowerCase()
			}, function (response){

				if ( response.success === true ) {
					$('.listItem').remove();
					Manager.list = {};
				}

				target.parent('.manager-installer').find('.feedback').html(response.message);
			}, 'json');//post end*/
		},
	},

	// CREATE NEW TEMPALTE
	'create': {
		eventType: 'click.create',
		selector: '[data-manager=create]',
		action: function(managerRef, target){
			var Manager = managerRef;

			modalHelper({
				modal: Manager.components['bootstrap-modal'].contents,
				view: Manager.components['manager-template-action'].contents,
				data:{
					action: 'Create Template'
				},
				title: 'Create New Template',
				shown: function(event, modal){

					$(modal).find('.templateAction').on('click.createTemplate', function(){

						if( $(modal).find('.templateName').val() === '' ){

							$(modal).find('.form-group').addClass('has-error');
							$(modal).find('.response').html('No Template Name Provided');
						} else {

							$.post(Manager.path.handler, {
								action: 'new',
								// template title
								templateName : $(modal).find('.templateName').val()
							}, function(response){
								if ( response.success === true) {
									$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
									$(modal).find('.response').html('');

									// add to template list
									Manager.list[response.ID] = {
										ID: response.ID,
										title: response.title,
										version:response.version,
										active: response.active
									};

									//render template
									Manager.renderList('active-list');

									setTimeout(function(){
										$(modal).modal('hide');
									}, 500);

								} else {
									$(modal).find('.form-group').addClass('has-error');
									// parse response
									var errMsg = objectToText(response.message);

									// append response
									$(modal).find('.response').html(errMsg);
								}
							}, 'json');// post end
						}
					});
				}
			});
		},
	},

	'update': {
		eventType: 'click.update',
		selector: '[data-manager=update]',
		action: function(managerRef, target){
			var Manager = managerRef;

			// template node
			var template = target.parents('[data-template-id]');
			// tempalte id
			var templateID = template.data('template-id');
			// Manager.list instance
			var templateInfo = Manager.list[templateID];

			modalHelper({
				modal: Manager.components['bootstrap-modal'].contents,
				view: Manager.components['manager-template-action'].contents,
				data:{
					action: 'Update template'
				},
				title: 'Update template',
				show: function(event, modal){
					$(modal).find('.templateName').val(templateInfo.title);
				},
				shown: function(event, modal){
					$(modal).find('.templateAction').on('click.updateTemplate', function(){
						var newTitle = $(modal).find('.templateName').val();

						// return if prompt is empty or canceled
						if ( newTitle === '' ) {

							$(modal).find('.form-group').addClass('has-error');
							$(modal).find('.response').html('No Title Provided.');
						} else {

							$.post(Manager.path.handler, {
								action: 'update',
								// template id
								templateID: templateID,
								//new template name
								newName: newTitle
							}, function(response){

								if ( response.success === true ) {
									$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
									$(modal).find('.response').html('');

									// replace title
									template.find('.template-title-link').html(newTitle);

									setTimeout(function(){
										$(modal).modal('hide');
									}, 500);
								} else {
									$(modal).find('.form-group').addClass('has-error');
									$(modal).find('.response').html(response.message);
								}
							}, 'json');//post end
						}// else
					}); //click.updateTemplate
				} //shown
			});// modelHelper
		}
	},

	'clone': {
		eventType: 'click.clone',
		selector: '[data-manager=clone]',
		action: function(managerRef, target){
			var Manager = managerRef;

			modalHelper({
				modal: Manager.components['bootstrap-modal'].contents,
				view: Manager.components['manager-template-action'].contents,
				data:{
					action: 'Template Name'
				},
				title: 'Clone Template',
				shown: function(event, modal){
					$(modal).find('.templateAction').on('click.cloneTemplate', function(){
						var newTitle = $(modal).find('.templateName').val();

						// return if prompt is empty or canceled
						if ( newTitle === '' ) {

							$(modal).find('.form-group').addClass('has-error');
							$(modal).find('.response').html('No Title Provided for New Template.');
						} else {

							$.post(Manager.path.handler, {
								action: 'clone',
								//template to be cloned ID
								cloneID: target.parents('[data-template-id]').data('template-id'),
								// new template name
								newTempName: $(modal).find('.templateName').val()
							}, function(response){
								if ( response.success === true ) {
									$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
									$(modal).find('.response').html('');

									// add to template list
									Manager.list[response.ID] = {
										ID: response.ID,
										title: response.title,
										version:response.version.toString(),
										active: response.active
									};
									//render template
									Manager.renderList('active-list');
									setTimeout(function(){
										$(modal).modal('hide');
									}, 500);
								} else {
									$(modal).find('.form-group').addClass('has-error');
									// parse response
									var errMsg = objectToText(response.message);

									// append response
									$(modal).find('.response').html(errMsg);
								}
							}, 'json');//post end
						}// else
					}); //click.cloneTemplate
				} //shown
			});// modelHelper
		}
	},

	'trash_delete': {
		eventType: 'click.trashDelete',
		selector: '[data-manager=trash], [data-manager=delete]',
		action: function(managerRef, target){
			var Manager = managerRef;
			// template node
			var template = target.parents('[data-template-id]');
			// template id
			var templateID = template.data('template-id');
			// Manager.list instance
			var templateInfo = Manager.list[templateID];

			modalHelper({
				modal: Manager.components['bootstrap-modal'].contents,
				view: Manager.components['manager-template-delete'].contents,
				data:{
					action: (templateInfo.active)? 'Move To Trash' : 'Permenetly Delete',
					isActive: templateInfo.active
				},
				title: (templateInfo.active)? 'Move To Trash' : 'Permenetly Delete',
				shown: function(event, modal){
					$(modal).find('.templateAction').on('click.delete', function(){
						$.post(Manager.path.handler, {
							action: 'delete',
							// temple id
							templateID: templateID,
							// template status
							isActive: Boolean(templateInfo.active)
						}, function(response){

							if ( response.success === true ) {
								$(modal).find('.form-group').addClass('has-success').removeClass('has-error');
								$(modal).find('.response').html('');

								template.remove();

								if ( templateInfo.active === true ) {
									templateInfo.active = false;
								} else {
									delete Manager.list[templateID];
								}

								setTimeout(function(){
									$(modal).modal('hide');
								}, 500);

							} else {
								// parse error response
								$(modal).find('.form-group').addClass('has-error');
								// parse response
								var errMsg = objectToText(response.message);

								// append response
								$(modal).find('.response').html(errMsg);
							}
						}, 'json');// post
					});
				}
			});
		}
	},

	'preview': {
		eventType: 'click.preview',
		selector: '[data-manager=preview]',
		action:function(managerRef, target){
			var Manager = managerRef;
			var template = target.parents('[data-template-id]');
			// template id
			var templateID = template.data('template-id');
			// Manager.list instance
			var templateInfo = Manager.list[templateID];
			var previewUrl = [
				'template=' + templateInfo.title,
				'id=' + templateInfo.ID,
				'version=' + templateInfo.version
			];
			window.open('/template/?' + previewUrl.join('&'), '_blank');
		}
	},

	'list-trash_list-active': {
		eventType: 'click.preview',
		selector: '[data-manager=list-trash], [data-manager=list-active]',
		action: function(managerRef, target){
			var Manager = managerRef;
			var listType = target.data('manager');

			// find active tab, remove class active if clicked tab is not active tab
			$('.templatesNavigations').find('.active').not($(target)).removeClass('active');

			$(target).addClass('active');

			// render if not active list
			if( $('[data-manager-list-type=' + listType + ']').size() === 0 ){
				Manager.renderList(listType);
			}
		}
	}
};

Manager.prototype.renderList = function(listType) {
	var Manager = this;
	var getActive = /active/.test(listType);

	var filterTemplates = _.filter(Manager.list, function(listItem) {
		console.log(Manager.list, listItem);
		return listItem.active == getActive;
	});

	filterTemplates.reverse();

	$('.manager-templates').handlebars({
		data:{
			templates: filterTemplates,
			listType: listType
		},
		view: Manager.components['manager-listing'].contents
	});
};<|endoftext|>


<commit_before>"use strict";
var IssueTrackingSystem = angular.module('IssueTrackingSystem', ['ngRoute', 'ngStorage']).constant('BASE_URL', 'http://softuni-issue-tracker.azurewebsites.net/');

IssueTrackingSystem.config(['$routeProvider', function ($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'app/template/home.html',
            controller: 'Main'
        }).when('/project', {
            templateUrl: 'app/template/project/project-add.html',
            controller: 'Main'
        }).otherwise({
            redirectTo: '/'
        });
}]);

IssueTrackingSystem.controller('Main', ['$scope', '$sessionStorage',
    function ($scope, $sessionStorage) {
    //if not authenticated
        if (!$sessionStorage.username || !$sessionStorage.isAuthenticated) {
            delete $sessionStorage.access_token;
            delete $sessionStorage.token_type;
            delete $sessionStorage.username;
            $sessionStorage.isAuthenticated = false;
            $scope.isAuthenticated = $sessionStorage.isAuthenticated;
        } else {
            $sessionStorage.isAuthenticated = true;
            $scope.isAuthenticated = $sessionStorage.isAuthenticated;
        }

        console.log($sessionStorage);
}]);<commit_msg>update with todo<commit_after>"use strict";
var IssueTrackingSystem = angular.module('IssueTrackingSystem', ['ngRoute', 'ngStorage']).constant('BASE_URL', 'http://softuni-issue-tracker.azurewebsites.net/');

IssueTrackingSystem.config(['$routeProvider', function ($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'app/template/home.html',
            controller: 'Main'
        }).when('/project', {
            templateUrl: 'app/template/project/project-add.html',
            controller: 'Main'
        }).otherwise({
            redirectTo: '/'
        });
}]);

IssueTrackingSystem.controller('Main', ['$scope', '$sessionStorage',
    function ($scope, $sessionStorage) {
    //if not authenticated
        if (!$sessionStorage.username || !$sessionStorage.isAuthenticated) {
            delete $sessionStorage.access_token;
            delete $sessionStorage.token_type;
            delete $sessionStorage.username;
            $sessionStorage.isAuthenticated = false;
            $scope.isAuthenticated = $sessionStorage.isAuthenticated;
        } else {
            $sessionStorage.isAuthenticated = true;
            $scope.isAuthenticated = $sessionStorage.isAuthenticated;
        }

        console.log($sessionStorage);   //TODO remove log session
}]);<|endoftext|>


<commit_before>//  buffer-tpc-check.js
//  (c) 2013 Sunil Sadasivan
//  Check if third party cookies are disabled
//

;(function () {

    ;(function check() {
        //if the 3rd party cookies check is done, remove the iframe
        if(self.port) {
            bufferpm.bind("buffer_3pc_done", function(){
                elem = document.getElementById('buffer_tpc_check');
                if(elem) { elem.parentNode.removeChild(elem); }
                return false;
            });

            //if the 3rd party cookies check is disabled, store it
            bufferpm.bind("buffer_3pc_disabled", function(){
                if(xt && xt.options) {
                    xt.options['buffer.op.tpc-disabled'] = true;
                }
                self.port.emit('buffer_tpc_disabled');
                return false;
            });

            var iframe = document.createElement('iframe');
            iframe.id = 'buffer_tpc_check';
            iframe.src = 'https://d3ijcis4e2ziok.cloudfront.net/tpc-check.html';
            //iframe.src = 'http://local.bufferapp.com/js/tpc-check.html';
            iframe.style.display="none";
            document.body.appendChild(iframe);
        } else {
            setTimeout(check, 50);
        }
    }());

}());
<commit_msg>Make TPC check work on chrome again<commit_after>//  buffer-tpc-check.js
//  (c) 2013 Sunil Sadasivan
//  Check if third party cookies are disabled
//

;(function () {

    ;(function check() {
        //if the 3rd party cookies check is done, remove the iframe
        if((self.port) || (xt && xt.options)) {
            bufferpm.bind("buffer_3pc_done", function(){
                elem = document.getElementById('buffer_tpc_check');
                if(elem) { elem.parentNode.removeChild(elem); }
                return false;
            });

            //if the 3rd party cookies check is disabled, store it
            bufferpm.bind("buffer_3pc_disabled", function(){
                if(xt && xt.options) {
                    xt.options['buffer.op.tpc-disabled'] = true;
                }
                self.port.emit('buffer_tpc_disabled');
                return false;
            });

            var iframe = document.createElement('iframe');
            iframe.id = 'buffer_tpc_check';
            iframe.src = 'https://d3ijcis4e2ziok.cloudfront.net/tpc-check.html';
            //iframe.src = 'http://local.bufferapp.com/js/tpc-check.html';
            iframe.style.display="none";
            document.body.appendChild(iframe);
        } else {
            setTimeout(check, 50);
        }
    }());

}());
<|endoftext|>


<commit_before>(function(){

// TODO Migrate this to use jinja.js, so we can place a template file in static/
//      and use that template on the server using an include statement and on
//      client side.
var result_template = ""
 + "
"
 + "
{{path_line}}
"
 + "{{formatted_lines}}"
 + "
";

var lines_template = ""
 + ""
 + "
"
 + "
{{line_number}}
"
 + "
"
 + "

{{line}}

"
 + "";

/** Format a template and return it */
function format_template(template, vars){
  for(var k in vars){
    var value = vars[k].toString().replace(new RegExp("\\$", "g"), "$$$$");
    template = template.replace(new RegExp("\\{\\{" + k + "\\}\\}", "g"), value);
  }
  return template;
}

/** Format results */
function format_results(data){
  // Fillout wwwroot and tree
  var result_tmpl = format_template(result_template, data);
  var lines_tmpl = format_template(lines_template, data);
  // For each result
  var retval = ""
  for(var i = 0; i < data["results"].length; i++){
    var lines = "";
    for(var j = 0; j < data["results"][i].lines.length; j++){
      lines += format_template(lines_tmpl, data["results"][i].lines[j]);
    }
    // Yes, the ugly path hack
    var folders = data["results"][i].path.split('/');
    var pathline = ""
    for(var j = 0; j < folders.length; j++){
      var folder = folders[j];
      var p = folders.slice(0, j + 1).join('/');
      var href = wwwroot + '/' + dxr.tree() + '/' + p;
      pathline += "<a href=\"" + href + "\" ";
      if(j + 1 < folders.length){
        pathline += "data-path=\"" + p + "/\"";
      }
      pathline += ">" + folder;
      if(j + 1 < folders.length){
        pathline += "/";
      }
      pathline += "";
    }
    retval += format_template(result_tmpl, {
      formatted_lines:    lines,
      path_line:          pathline,
      icon:               data["results"][i].icon,
      path:               data["results"][i].path
    });
  }
  return retval;
}

/* Check if we've scrolled to bottom of the page
 * Find scroll top and test if we're at the bottom
 * http://stackoverflow.com/questions/10059888/ */
function atPageBottom(){
  var scrollTop = Math.max(document.documentElement.scrollTop,
                           document.body.scrollTop);
  scrollTop += document.documentElement.clientHeight;
  return scrollTop >= document.documentElement.scrollHeight;
}

/** Initialize incremental search, etc. */
function initIncrementalSearch(){
  // Get the query as passed in the text field
  var q = document.getElementById("query");
  state.query = q.value;

  // Since we have javascript support let's hide paging links
  var pagelinks = document.getElementById("result-page-switch");
  if(pagelinks){
    // If we're in the search.html template, we hide the foot
    // If not we'll do this in fetch_results, when we got something
    var foot = document.getElementById("foot");
    foot.style.display        = 'none';
    // Display the fetcher thing with visibility hidden
    var fetcher = document.getElementById("fetch-results");
    fetcher.style.display     = 'block';
    fetcher.style.visibility  = 'hidden';
  }

  // Fetch results, if any, on scroll to bottom of page
  window.addEventListener('scroll', function(e){
    if(atPageBottom() && !state.eof) fetch_results(true);
  }, false);

  // Update advanced search fields on change in q
  q.addEventListener('input', function(e){
    // Don't do anything if query didn't change
    if(state.query == q.value) return;
    // Reset the state
    state.query   = q.value;
    state.offset  = 0;
    state.eof     = false;
    state.changed = true;
    // Dispatch dxr-state-changed
    window.dispatchEvent(
      new CustomEvent( 'dxr-state-changed', {
        detail: {}
      })
    );
  }, false);

  // Set fetch results time when state is changed
  window.addEventListener('dxr-state-changed', setFetchResultsTimer);

  document.getElementById("tree").addEventListener('change', function(){
    state.query   = q.value;
    state.offset  = 0;
    state.eof     = false;
    state.changed = true;
    // Dispatch dxr-state-changed
    window.dispatchEvent(
      new CustomEvent( 'dxr-state-changed', {
        detail: {}
      })
    );
  }, false);

  // Fetch results if a bottom of page initially
  // this is necessary, otherwise one can't scroll
  if(atPageBottom() && !state.eof) fetch_results(true);
}

/** Set fetch results timer  */
var _fetch_results_timer = null;
function setFetchResultsTimer(){
  var timeout = 300;  // use 300 ms
  // Reset the timer
  if(_fetch_results_timer) clearTimeout(_fetch_results_timer);
  _fetch_results_timer = setTimeout(fetch_results, timeout);
}

// Current request
var request = null;
// Clear contents of results on set
var clear_on_set = false;

/** Fetch results, using current state */
function fetch_results(display_fetcher){

  // Stop if we're at end, nothing more to do
  if(state.eof && !state.changed) return;

  // Only request results if no pending request is in progress
  if(request && !state.changed) return;

  // Abort request if in progress
  if(request){
    // Clear event handler
    request.onreadystatechange = null;
    request.abort();
  }

  // Show the fetcher line at the bottom
  var fetcher = document.getElementById("fetch-results");
  if(display_fetcher){
    fetcher.style.visibility = 'visible';
    fetcher.style.display    = 'block';
    // Hide footer
    var foot = document.getElementById("foot");
    foot.style.display       = 'none';
  }

  // Create request
  request = new XMLHttpRequest();
  request.onreadystatechange = function(){
    if(request.readyState == 4 && request.status == 200){
      // Get data
      var data = JSON.parse(request.responseText);
      // Update state, if it wasn't changed
      if(!state.changed){
        state.eof     = data["results"].length == 0;
        state.offset += data["results"].length;
      }
      // Display a nice tip
      dxr.setTip("Incremental search results in " + data["time"].toFixed(3) + "s");
      var content = document.getElementById("content");
      // Clear results if necessary
      if(clear_on_set && !data["error"]){
        content.innerHTML = "";
        // Scroll to top of page
        window.scroll(0, 0);

        // Hide foot, set fetcher hidden
        var foot = document.getElementById("foot");
        foot.style.display       = 'none';
        fetcher.style.display    = 'block';
        fetcher.style.visibility = 'hidden';
      }
      content.innerHTML += format_results(data);
      // Set error as tip
      if(data["error"])
        dxr.setErrorTip(data["error"]);
      request = null;
    }else if(request.readyState == 4){
      // Something failed, who cares try again :)
      request = null;
      fetch_results();
    }
    // Hide fetcher if finished request
    if(request == null){
      fetcher.style.display    = 'block';
      fetcher.style.visibility = 'hidden';
      // Fetch results if there's no scrollbar initially
      if(atPageBottom()) fetch_results();
    }
  }

  // Clear on set if this is a new state
  clear_on_set = state.changed;
  // Set state unchanged
  state.changed = false;

  // parameters for request
  var params = {
    q:              state.query,
    tree:           dxr.tree(),
    limit:          state.limit,
    offset:         state.offset,
    redirect:       'false',
    format:         'json'
  };

  // Start a new request
  request.open("GET", createSearchUrl(params), true);
  request.send();
}

/** Parse querystring */
function parseQuerystring(){
  var params = {};
  var items = window.location.search.substr(1).split("&");
  for(var i = 0; i < items.length; i++){
    var keyvalue = items[i].split("=");
    params[decodeURIComponent(keyvalue[0])] = decodeURIComponent(keyvalue[1]);
  }
  return params;
}

/** Create search URL from search parameters as querystring */
function createSearchUrl(params){
  var elements = []
  for(var key in params){
    var k = encodeURIComponent(key);
    var v = encodeURIComponent(params[key]);
    elements.push(k + "=" + v);
  }
  return wwwroot + "/search?" + elements.join("&");
}
window.createSearchUrl = createSearchUrl;  // used in advanced-search.js

/** Initialize the context menu */
function initMenu(){
  // Show menu when path link is clicked
  // Attach event handler on results, so we don't have to worry about what
  // happens when we update the contents of results.
  document.getElementById("content").addEventListener('click', function (e){
    // Ensure that we're in a
    if(!e.target.parentNode
       || !e.target.parentNode.classList.contains('path')) return;

    // Okay, get the path
    var path = e.target.dataset.path;

    // Don't show menu if file name part was clicked
    // as we didn't stop default user will jump to this page
    if(!path) return;

    // Parse querystring so we can make some urls
    var params = {
      tree:           dxr.tree(),
      limit:          state.limit,
      redirect:       'false'
    };

    // Create url to limit search
    params.q = state.query + " path:" + path;
    var limit_url = createSearchUrl(params);

    // Create url to exclude path from search
    params.q = state.query + " -path:" + path;
    var exclude_url = createSearchUrl(params);

    // Populate menu with links
    menu.populate([
      {
        icon:   'goto_folder',
        href:    wwwroot + "/" + dxr.tree() + "/" + path,
        title:  "Browse the \"" + path + "\" folder",
        text:   "Browser folder contents"
      },
      {
        icon:   'path_search',
        href:   limit_url,
        title:  "Only show results from \"" + path + "\"",
        text:   "Limit search to folder"
      },
      {
        icon:   'exclude_path',
        href:   exclude_url,
        title:  "Exclude results located in \"" + path + "\"",
        text:   "Exclude folder from search"
      }
    ]);
    // Launch menu
    menu.launch(e.target);
    // Stop event propagation
    e.preventDefault();
    e.stopPropagation();
  }, false);
}

/** Subscribe to events */
window.addEventListener('load', function(){
  initIncrementalSearch();
  initMenu();
}, false);

}());
<commit_msg>Notify user when a search request is pending in the background.<commit_after>(function(){

// TODO Migrate this to use jinja.js, so we can place a template file in static/
//      and use that template on the server using an include statement and on
//      client side.
var result_template = ""
 + "
"
 + "
{{path_line}}
"
 + "{{formatted_lines}}"
 + "
";

var lines_template = ""
 + ""
 + "
"
 + "
{{line_number}}
"
 + "
"
 + "

{{line}}

"
 + "";

/** Format a template and return it */
function format_template(template, vars){
  for(var k in vars){
    var value = vars[k].toString().replace(new RegExp("\\$", "g"), "$$$$");
    template = template.replace(new RegExp("\\{\\{" + k + "\\}\\}", "g"), value);
  }
  return template;
}

/** Format results */
function format_results(data){
  // Fillout wwwroot and tree
  var result_tmpl = format_template(result_template, data);
  var lines_tmpl = format_template(lines_template, data);
  // For each result
  var retval = ""
  for(var i = 0; i < data["results"].length; i++){
    var lines = "";
    for(var j = 0; j < data["results"][i].lines.length; j++){
      lines += format_template(lines_tmpl, data["results"][i].lines[j]);
    }
    // Yes, the ugly path hack
    var folders = data["results"][i].path.split('/');
    var pathline = ""
    for(var j = 0; j < folders.length; j++){
      var folder = folders[j];
      var p = folders.slice(0, j + 1).join('/');
      var href = wwwroot + '/' + dxr.tree() + '/' + p;
      pathline += "<a href=\"" + href + "\" ";
      if(j + 1 < folders.length){
        pathline += "data-path=\"" + p + "/\"";
      }
      pathline += ">" + folder;
      if(j + 1 < folders.length){
        pathline += "/";
      }
      pathline += "";
    }
    retval += format_template(result_tmpl, {
      formatted_lines:    lines,
      path_line:          pathline,
      icon:               data["results"][i].icon,
      path:               data["results"][i].path
    });
  }
  return retval;
}

/* Check if we've scrolled to bottom of the page
 * Find scroll top and test if we're at the bottom
 * http://stackoverflow.com/questions/10059888/ */
function atPageBottom(){
  var scrollTop = Math.max(document.documentElement.scrollTop,
                           document.body.scrollTop);
  scrollTop += document.documentElement.clientHeight;
  return scrollTop >= document.documentElement.scrollHeight;
}

/** Initialize incremental search, etc. */
function initIncrementalSearch(){
  // Get the query as passed in the text field
  var q = document.getElementById("query");
  state.query = q.value;

  // Since we have javascript support let's hide paging links
  var pagelinks = document.getElementById("result-page-switch");
  if(pagelinks){
    // If we're in the search.html template, we hide the foot
    // If not we'll do this in fetch_results, when we got something
    var foot = document.getElementById("foot");
    foot.style.display        = 'none';
    // Display the fetcher thing with visibility hidden
    var fetcher = document.getElementById("fetch-results");
    fetcher.style.display     = 'block';
    fetcher.style.visibility  = 'hidden';
  }

  // Fetch results, if any, on scroll to bottom of page
  window.addEventListener('scroll', function(e){
    if(atPageBottom() && !state.eof) fetch_results(true);
  }, false);

  // Update advanced search fields on change in q
  q.addEventListener('input', function(e){
    // Don't do anything if query didn't change
    if(state.query == q.value) return;
    // Reset the state
    state.query   = q.value;
    state.offset  = 0;
    state.eof     = false;
    state.changed = true;
    // Dispatch dxr-state-changed
    window.dispatchEvent(
      new CustomEvent( 'dxr-state-changed', {
        detail: {}
      })
    );
  }, false);

  // Set fetch results time when state is changed
  window.addEventListener('dxr-state-changed', setFetchResultsTimer);

  document.getElementById("tree").addEventListener('change', function(){
    state.query   = q.value;
    state.offset  = 0;
    state.eof     = false;
    state.changed = true;
    // Dispatch dxr-state-changed
    window.dispatchEvent(
      new CustomEvent( 'dxr-state-changed', {
        detail: {}
      })
    );
  }, false);

  // Fetch results if a bottom of page initially
  // this is necessary, otherwise one can't scroll
  if(atPageBottom() && !state.eof) fetch_results(true);
}

/** Set fetch results timer  */
var _fetch_results_timer = null;
function setFetchResultsTimer(){
  var timeout = 300;  // use 300 ms
  // Reset the timer
  if(_fetch_results_timer) clearTimeout(_fetch_results_timer);
  _fetch_results_timer = setTimeout(fetch_results, timeout);
}

// Current request
var request = null;
// Clear contents of results on set
var clear_on_set = false;

/** Fetch results, using current state */
function fetch_results(display_fetcher){

  // Stop if we're at end, nothing more to do
  if(state.eof && !state.changed) return;

  // Only request results if no pending request is in progress
  if(request && !state.changed) return;

  // Abort request if in progress
  if(request){
    // Clear event handler
    request.onreadystatechange = null;
    request.abort();
  }

  // Show the fetcher line at the bottom
  var fetcher = document.getElementById("fetch-results");
  if(display_fetcher){
    fetcher.style.visibility = 'visible';
    fetcher.style.display    = 'block';
    // Hide footer
    var foot = document.getElementById("foot");
    foot.style.display       = 'none';
  }

  // Create request
  request = new XMLHttpRequest();
  request.onreadystatechange = function(){
    if(request.readyState == 4 && request.status == 200){
      // Get data
      var data = JSON.parse(request.responseText);
      // Update state, if it wasn't changed
      if(!state.changed){
        state.eof     = data["results"].length == 0;
        state.offset += data["results"].length;
      }
      // Display a nice tip
      dxr.setTip("Incremental search results in " + data["time"].toFixed(3) + "s");
      var content = document.getElementById("content");
      // Clear results if necessary
      if(clear_on_set && !data["error"]){
        content.innerHTML = "";
        // Scroll to top of page
        window.scroll(0, 0);

        // Hide foot, set fetcher hidden
        var foot = document.getElementById("foot");
        foot.style.display       = 'none';
        fetcher.style.display    = 'block';
        fetcher.style.visibility = 'hidden';
      }
      content.innerHTML += format_results(data);
      // Set error as tip
      if(data["error"])
        dxr.setErrorTip(data["error"]);
      request = null;
    }else if(request.readyState == 4){
      // Something failed, who cares try again :)
      request = null;
      fetch_results();
    }
    // Hide fetcher if finished request
    if(request == null){
      fetcher.style.display    = 'block';
      fetcher.style.visibility = 'hidden';
      // Fetch results if there's no scrollbar initially
      if(atPageBottom()) fetch_results();
    }
  }

  // Clear on set if this is a new state
  clear_on_set = state.changed;
  // Set state unchanged
  state.changed = false;

  // parameters for request
  var params = {
    q:              state.query,
    tree:           dxr.tree(),
    limit:          state.limit,
    offset:         state.offset,
    redirect:       'false',
    format:         'json'
  };

  // Start a new request
  request.open("GET", createSearchUrl(params), true);
  dxr.setTip("Search in progress ...");
  request.send();
}

/** Parse querystring */
function parseQuerystring(){
  var params = {};
  var items = window.location.search.substr(1).split("&");
  for(var i = 0; i < items.length; i++){
    var keyvalue = items[i].split("=");
    params[decodeURIComponent(keyvalue[0])] = decodeURIComponent(keyvalue[1]);
  }
  return params;
}

/** Create search URL from search parameters as querystring */
function createSearchUrl(params){
  var elements = []
  for(var key in params){
    var k = encodeURIComponent(key);
    var v = encodeURIComponent(params[key]);
    elements.push(k + "=" + v);
  }
  return wwwroot + "/search?" + elements.join("&");
}
window.createSearchUrl = createSearchUrl;  // used in advanced-search.js

/** Initialize the context menu */
function initMenu(){
  // Show menu when path link is clicked
  // Attach event handler on results, so we don't have to worry about what
  // happens when we update the contents of results.
  document.getElementById("content").addEventListener('click', function (e){
    // Ensure that we're in a
    if(!e.target.parentNode
       || !e.target.parentNode.classList.contains('path')) return;

    // Okay, get the path
    var path = e.target.dataset.path;

    // Don't show menu if file name part was clicked
    // as we didn't stop default user will jump to this page
    if(!path) return;

    // Parse querystring so we can make some urls
    var params = {
      tree:           dxr.tree(),
      limit:          state.limit,
      redirect:       'false'
    };

    // Create url to limit search
    params.q = state.query + " path:" + path;
    var limit_url = createSearchUrl(params);

    // Create url to exclude path from search
    params.q = state.query + " -path:" + path;
    var exclude_url = createSearchUrl(params);

    // Populate menu with links
    menu.populate([
      {
        icon:   'goto_folder',
        href:    wwwroot + "/" + dxr.tree() + "/" + path,
        title:  "Browse the \"" + path + "\" folder",
        text:   "Browser folder contents"
      },
      {
        icon:   'path_search',
        href:   limit_url,
        title:  "Only show results from \"" + path + "\"",
        text:   "Limit search to folder"
      },
      {
        icon:   'exclude_path',
        href:   exclude_url,
        title:  "Exclude results located in \"" + path + "\"",
        text:   "Exclude folder from search"
      }
    ]);
    // Launch menu
    menu.launch(e.target);
    // Stop event propagation
    e.preventDefault();
    e.stopPropagation();
  }, false);
}

/** Subscribe to events */
window.addEventListener('load', function(){
  initIncrementalSearch();
  initMenu();
}, false);

}());
<|endoftext|>


<commit_before>/** @jsx React.DOM */
var NavigationBar = require('../navigation-bar/component');
var EditorAndRunner = require('../editor-and-runner/component');
var KeyboardShortcutOverlay = require('../keyboard-shortcut-overlay/component');

var React = require('react');

var View = React.createClass({

  render: function() {
    return (

        <NavigationBar metaKeySymbol={this.props.metaKeySymbol} onSave={this.props.onSave}/>
        <EditorAndRunner editorId={this.props.editorId} runnerId={this.props.runnerId}/>
        <KeyboardShortcutOverlay shortcuts={this.props.shortcuts}/>

    );
  }

});

module.exports = View;
<commit_msg>Add isVisible to shortcuts overlay and extracted `props=this.props`.<commit_after>/** @jsx React.DOM */
var NavigationBar = require('../navigation-bar/component');
var EditorAndRunner = require('../editor-and-runner/component');
var KeyboardShortcutOverlay = require('../keyboard-shortcut-overlay/component');

var React = require('react');

var View = React.createClass({

  render: function() {
    var props = this.props;
    return (

        <NavigationBar metaKeySymbol={props.metaKeySymbol} onSave={props.onSave}/>
        <EditorAndRunner editorId={props.editorId} runnerId={props.runnerId}/>
        <KeyboardShortcutOverlay shortcuts={props.shortcuts} isVisible={props.shortcutOverlay.isVisible}/>

    );
  }

});

module.exports = View;
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  extends: 'airbnb',
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 7,
    sourceType: 'module',
  },
  env: {
    jest: true,
    browser: true,
  },
  rules: {
    'max-len': ['error', 120, 2, {
      ignoreUrls: true,
    }],
    semi: ['error', 'never'],
    'no-shadow': 'off',
    'no-param-reassign': 'off',
    'no-nested-ternary': 'off',
    'no-use-before-define': ['error', { functions: false, classes: false }],

    'react/jsx-filename-extension': ['error', { extensions: ['.js'] }],
    'react/prop-types': 'off',
    'react/require-default-props': 'off',
    'react/forbid-prop-types': 'off',

    'import/prefer-default-export': 'off',
  },
  settings: {
    'import/resolver': {
      node: {
        // As configured in webpack and jest
        moduleDirectory: ['node_modules', 'src'],
      },
    },
  },
}
<commit_msg>chore: max-len => 100<commit_after>module.exports = {
  root: true,
  extends: 'airbnb',
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 7,
    sourceType: 'module',
  },
  env: {
    jest: true,
    browser: true,
  },
  rules: {
    'max-len': ['error', 100, 2, { ignoreUrls: true }],
    semi: ['error', 'never'],
    'no-shadow': 'off',
    'no-param-reassign': 'off',
    'no-nested-ternary': 'off',
    'no-use-before-define': ['error', { functions: false, classes: false }],

    'react/jsx-filename-extension': ['error', { extensions: ['.js'] }],
    'react/prop-types': 'off',
    'react/require-default-props': 'off',
    'react/forbid-prop-types': 'off',

    'import/prefer-default-export': 'off',
  },
  settings: {
    'import/resolver': {
      node: {
        // As configured in webpack and jest
        moduleDirectory: ['node_modules', 'src'],
      },
    },
  },
}
<|endoftext|>