<commit_before>import Tasking from '../../../../src/screens/assignment-builder/builder/tasking';
import UX from '../../../../src/screens/assignment-builder/ux';
import { Factory, TimeMock, moment } from '../../../helpers';

describe('Tasking Builder', () => {

  let props, plan, course;
  const now = TimeMock.setTo('2015-10-14T12:00:00.000Z');

  beforeEach(() => {
    course = Factory.course();
    plan = Factory.teacherTaskPlan({ course });
    const ux = new UX({ course, plan });
    props = { ux };
  });

  it('sets times', function() {
    const tasking = mount(<Tasking {...props} />);

    const opens_at = moment(now).add(1, 'day');
    const due_at = moment(now).add(3, 'day');

    tasking.find('.opens-at TutorDateInput input[onChange]')
      .simulate('change', { target: { value: opens_at.format('MM/DD/YYYY') } });
    tasking.find('.opens-at TutorTimeInput input').simulate('change', {
      target: { value: '8:22 pm' },
    });

    expect(
      tasking.find('.due-at TutorDateInput').props().min.toISOString()
    ).toEqual('2015-10-16T01:22:00.000Z');

    tasking.find('.due-at TutorDateInput input[onChange]')
      .simulate('change', { target: { value: due_at.format('MM/DD/YYYY') } });

    tasking.find('.due-at TutorTimeInput input').simulate('change', {
      target: { value: '945am' },
    });

    expect(
      tasking.find('.opens-at TutorDateInput').props().max.toISOString()
    ).toEqual(due_at.clone().hour(9).minute(45).toISOString());

    tasking.unmount();
  });

  it('toggles a period inclusion', () => {
    const [ period ] = course.periods;
    props.period = period;
    const tasking = mount(<Tasking {...props} />);

    tasking.find('input[type="checkbox"]').simulate('change', {
      target: { dataset: { periodId: period.id }, checked: false },
    });
    expect(plan.tasking_plans.forPeriod(period)).toBeUndefined();
    expect(tasking).not.toHaveRendered('.tasking-date-time');

    tasking.find('input[type="checkbox"]').simulate('change', {
      target: { dataset: { periodId: period.id }, checked: true },
    });
    expect(tasking).toHaveRendered('.tasking-date-time');
    expect(plan.tasking_plans.forPeriod(period)).toBeTruthy();

    tasking.unmount();
  });

});
<commit_msg>update spec<commit_after>import Tasking from '../../../../src/screens/assignment-builder/builder/tasking';
import UX from '../../../../src/screens/assignment-builder/ux';
import { Factory, TimeMock, moment } from '../../../helpers';

describe('Tasking Builder', () => {

  let props, plan, course;
  const now = TimeMock.setTo('2015-10-14T12:00:00.000Z');

  beforeEach(() => {
    course = Factory.course();
    plan = Factory.teacherTaskPlan({ course });
    const ux = new UX({ course, plan });
    props = { ux };
  });

  it('sets times', function() {
    const tasking = mount(<Tasking {...props} />);

    const opens_at = moment(now).add(1, 'day');
    const due_at = moment(now).add(3, 'day');

    tasking.find('.opens-at TutorDateInput input[onChange]')
      .simulate('change', { target: { value: opens_at.format('MM/DD/YYYY') } });
    tasking.find('.opens-at TutorTimeInput input').simulate('change', {
      target: { value: '8:22' },
    });

    expect(
      tasking.find('.due-at TutorDateInput').props().min.toISOString()
    ).toEqual(moment(opens_at).hour(8).minute(22).toISOString());

    tasking.find('.due-at TutorDateInput input[onChange]')
      .simulate('change', { target: { value: due_at.format('MM/DD/YYYY') } });

    tasking.find('.due-at TutorTimeInput input').simulate('change', {
      target: { value: '9:45' },
    });

    expect(
      tasking.find('.opens-at TutorDateInput').props().max.toISOString()
    ).toEqual(due_at.clone().hour(9).minute(45).toISOString());

    tasking.unmount();
  });

  it('toggles a period inclusion', () => {
    const [ period ] = course.periods;
    props.period = period;
    const tasking = mount(<Tasking {...props} />);

    tasking.find('input[type="checkbox"]').simulate('change', {
      target: { dataset: { periodId: period.id }, checked: false },
    });
    expect(plan.tasking_plans.forPeriod(period)).toBeUndefined();
    expect(tasking).not.toHaveRendered('.tasking-date-time');

    tasking.find('input[type="checkbox"]').simulate('change', {
      target: { dataset: { periodId: period.id }, checked: true },
    });
    expect(tasking).toHaveRendered('.tasking-date-time');
    expect(plan.tasking_plans.forPeriod(period)).toBeTruthy();

    tasking.unmount();
  });

});
<|endoftext|>


<commit_before>var productMgr = (function (config, functions) {

    return {
        searchParams: {
            dataCategory: -1,//-1表示所有数据，0表示搜索标签，1表示搜索状态和货号
            brand: [],
            category: [],
            date: [],
            color: [],
            size: []
        },
        loadedData: {},
        showDetail: function (id) {
            var data = this.loadedData[id];
            $(".mustSetValue").each(function (index, el) {
                $(this).text(data[$(this).data("name")]);
            })
            $(".mustSetSrc").each(function (index, el) {
                $(this).attr("src", data[$(this).data("name")]);
            })
            $("#showDetailModal").modal("show");
        }
    }
})(config, functions);

$(document).ready(function () {

    var table = new ZYTableHandler({
        removeUrl: "#",
        ownTable: function () {
            var ownTable = $("#myTable").dataTable({
                "bServerSide": true,
                "sAjaxSource": config.ajaxUrls.productGetAll,
                "bInfo": true,
                "bProcessing": true,
                "bLengthChange": false,
                "bFilter": false,
                "bSort": false,
                "bAutoWidth": false,
                "iDisplayLength": config.perLoadCounts.table,
                "sPaginationType": "full_numbers",
                "oLanguage": {
                    "sUrl": config.dataTable.langUrl
                },
                "aoColumns": [
                    { "mDataProp": "imageUrl3",
                        "fnRender": function (oObj) {
                            return  '';
                        }
                    },
                    { "mDataProp": "hp_num"},
                    { "mDataProp": "brandList"},
                    { "mDataProp": "categoryList"},
                    { "mDataProp": "timeCategoryList"},
                    { "mDataProp": "dataStatus",
                        "fnRender": function (oObj) {
                            return  config.status.product[oObj.aData.dataStatus];
                        }
                    },
                    { "mDataProp": "opt",
                        "fnRender": function (oObj) {
                            return  '查看  ' +
                                '编辑  ' +
                                '作废';
                        }
                    }
                ],
                "fnServerParams": function (aoData) {
                    aoData.push({
                        name: "dataCategory",
                        value: productMgr.searchParams.dataCategory
                    }, {
                        name: "dataStatus",
                        value: $("#searchStatus").val()
                    }, {
                        name: "hp_num",
                        value: $("#searchNo").val()
                    }, {
                        name: "brand",
                        value: productMgr.searchParams.brand.join(",")
                    }, {
                        name: "category",
                        value: productMgr.searchParams.category.join(",")
                    }, {
                        name: "date",
                        value: productMgr.searchParams.date.join(",")
                    }, {
                        name: "size",
                        value: productMgr.searchParams.size.join(",")
                    }, {
                        name: "color",
                        value: productMgr.searchParams.color.join(",")
                    })
                },
                "fnServerData": function (sSource, aoData, fnCallback) {

                    //回调函数
                    $.ajax({
                        "dataType": 'json',
                        "type": "get",
                        "url": sSource,
                        "data": aoData,
                        "success": function (response) {
                            if (response.success === false) {
                                functions.ajaxReturnErrorHandler(response.message);
                            } else {
                                var json = {
                                    "sEcho": response.sEcho
                                };

                                productMgr.loadedData = {};

                                for (var i = 0, iLen = response.aaData.length; i < iLen; i++) {
                                    response.aaData[i].opt = "opt";
                                    response.aaData[i].dataStatusString=config.status.product[response.aaData[i].dataStatus];
                                    productMgr.loadedData[response.aaData[i].id] = response.aaData[i];
                                }

                                json.aaData = response.aaData;
                                json.iTotalRecords = response.iTotalRecords;
                                json.iTotalDisplayRecords = response.iTotalDisplayRecords;
                                fnCallback(json);
                            }

                        }
                    });
                },
                "fnFormatNumber": function (iIn) {
                    return iIn;
                }
            });

            return ownTable;
        }
    });

    $("#myTable").on("click", "a.remove",function () {
        if (confirm(config.messages.confirmDelete)) {
            table.delete($(this).attr("href"));
        }
        return false;
    }).on("click", "a.check", function () {
            productMgr.showDetail($(this).attr("href"));
            return false;
        });

    $("#searchBtn").click(function () {
        productMgr.searchParams = {
            dataCategory: 1,
            brand: [],
            category: [],
            date: [],
            color: [],
            size: []
        };

        //后台没有处理dataStatus为-1（全部）的情况，如果status为-1，并且No为空，那就是直接查所有数据
        if ($("#searchStatus").val() == -1 && !$("#searchNo").val()) {
            productMgr.searchParams.dataCategory = -1;
        }

        $("#searchPanel .active").removeClass("active");
        table.tableRedraw();
    });

    $("#searchPanel").on("click", ".item", function () {
        var el = $(this),
            type = el.data("type"),
            id = el.data("id"),
            index;

        $("#searchNo").val("");
        $("#searchStatus").val(-1);

        if (el.hasClass("active")) {
            index = productMgr.searchParams[type].indexOf(id);
            productMgr.searchParams[type].splice(index, 1);
            el.removeClass("active");
        } else {
            productMgr.searchParams[type].push(id);
            el.addClass("active");
        }

        if ($("#searchPanel .active").length == 0) {
            productMgr.searchParams.dataCategory = -1;
        } else {
            productMgr.searchParams.dataCategory = 0;
        }
        table.tableRedraw();
    });

    $("#searchPanelCtrl").click(function () {
        if ($(this).data("target").indexOf("down") != -1) {
            $("#searchPanel .row").hide(400);
            $(this).find(".glyphicon").removeClass("glyphicon-chevron-up").addClass("glyphicon-chevron-down");
            $(this).data("target", "up");
            $(this).find(".text").text("展开选项");
        } else {
            $("#searchPanel .row").show(400);
            $(this).find(".glyphicon").removeClass("glyphicon-chevron-down").addClass("glyphicon-chevron-up");
            $(this).data("target", "down");
            $(this).find(".text").text("收起选项");
        }

    });

});<commit_msg>去掉货品管理的作废按钮<commit_after>var productMgr = (function (config, functions) {

    return {
        searchParams: {
            dataCategory: -1,//-1表示所有数据，0表示搜索标签，1表示搜索状态和货号
            brand: [],
            category: [],
            date: [],
            color: [],
            size: []
        },
        loadedData: {},
        showDetail: function (id) {
            var data = this.loadedData[id];
            $(".mustSetValue").each(function (index, el) {
                $(this).text(data[$(this).data("name")]);
            })
            $(".mustSetSrc").each(function (index, el) {
                $(this).attr("src", data[$(this).data("name")]);
            })
            $("#showDetailModal").modal("show");
        }
    }
})(config, functions);

$(document).ready(function () {

    var table = new ZYTableHandler({
        removeUrl: "#",
        ownTable: function () {
            var ownTable = $("#myTable").dataTable({
                "bServerSide": true,
                "sAjaxSource": config.ajaxUrls.productGetAll,
                "bInfo": true,
                "bProcessing": true,
                "bLengthChange": false,
                "bFilter": false,
                "bSort": false,
                "bAutoWidth": false,
                "iDisplayLength": config.perLoadCounts.table,
                "sPaginationType": "full_numbers",
                "oLanguage": {
                    "sUrl": config.dataTable.langUrl
                },
                "aoColumns": [
                    { "mDataProp": "imageUrl3",
                        "fnRender": function (oObj) {
                            return  '';
                        }
                    },
                    { "mDataProp": "hp_num"},
                    { "mDataProp": "brandList"},
                    { "mDataProp": "categoryList"},
                    { "mDataProp": "timeCategoryList"},
                    { "mDataProp": "dataStatus",
                        "fnRender": function (oObj) {
                            return  config.status.product[oObj.aData.dataStatus];
                        }
                    },
                    { "mDataProp": "opt",
                        "fnRender": function (oObj) {
                            /*return  '查看  ' +
                                '编辑  ' +
                                '作废';*/
                            return  '查看  ' +
                                '编辑';
                        }
                    }
                ],
                "fnServerParams": function (aoData) {
                    aoData.push({
                        name: "dataCategory",
                        value: productMgr.searchParams.dataCategory
                    }, {
                        name: "dataStatus",
                        value: $("#searchStatus").val()
                    }, {
                        name: "hp_num",
                        value: $("#searchNo").val()
                    }, {
                        name: "brand",
                        value: productMgr.searchParams.brand.join(",")
                    }, {
                        name: "category",
                        value: productMgr.searchParams.category.join(",")
                    }, {
                        name: "date",
                        value: productMgr.searchParams.date.join(",")
                    }, {
                        name: "size",
                        value: productMgr.searchParams.size.join(",")
                    }, {
                        name: "color",
                        value: productMgr.searchParams.color.join(",")
                    })
                },
                "fnServerData": function (sSource, aoData, fnCallback) {

                    //回调函数
                    $.ajax({
                        "dataType": 'json',
                        "type": "get",
                        "url": sSource,
                        "data": aoData,
                        "success": function (response) {
                            if (response.success === false) {
                                functions.ajaxReturnErrorHandler(response.message);
                            } else {
                                var json = {
                                    "sEcho": response.sEcho
                                };

                                productMgr.loadedData = {};

                                for (var i = 0, iLen = response.aaData.length; i < iLen; i++) {
                                    response.aaData[i].opt = "opt";
                                    response.aaData[i].dataStatusString=config.status.product[response.aaData[i].dataStatus];
                                    productMgr.loadedData[response.aaData[i].id] = response.aaData[i];
                                }

                                json.aaData = response.aaData;
                                json.iTotalRecords = response.iTotalRecords;
                                json.iTotalDisplayRecords = response.iTotalDisplayRecords;
                                fnCallback(json);
                            }

                        }
                    });
                },
                "fnFormatNumber": function (iIn) {
                    return iIn;
                }
            });

            return ownTable;
        }
    });

    $("#myTable").on("click", "a.remove",function () {
        if (confirm(config.messages.confirmDelete)) {
            table.delete($(this).attr("href"));
        }
        return false;
    }).on("click", "a.check", function () {
            productMgr.showDetail($(this).attr("href"));
            return false;
        });

    $("#searchBtn").click(function () {
        productMgr.searchParams = {
            dataCategory: 1,
            brand: [],
            category: [],
            date: [],
            color: [],
            size: []
        };

        //后台没有处理dataStatus为-1（全部）的情况，如果status为-1，并且No为空，那就是直接查所有数据
        if ($("#searchStatus").val() == -1 && !$("#searchNo").val()) {
            productMgr.searchParams.dataCategory = -1;
        }

        $("#searchPanel .active").removeClass("active");
        table.tableRedraw();
    });

    $("#searchPanel").on("click", ".item", function () {
        var el = $(this),
            type = el.data("type"),
            id = el.data("id"),
            index;

        $("#searchNo").val("");
        $("#searchStatus").val(-1);

        if (el.hasClass("active")) {
            index = productMgr.searchParams[type].indexOf(id);
            productMgr.searchParams[type].splice(index, 1);
            el.removeClass("active");
        } else {
            productMgr.searchParams[type].push(id);
            el.addClass("active");
        }

        if ($("#searchPanel .active").length == 0) {
            productMgr.searchParams.dataCategory = -1;
        } else {
            productMgr.searchParams.dataCategory = 0;
        }
        table.tableRedraw();
    });

    $("#searchPanelCtrl").click(function () {
        if ($(this).data("target").indexOf("down") != -1) {
            $("#searchPanel .row").hide(400);
            $(this).find(".glyphicon").removeClass("glyphicon-chevron-up").addClass("glyphicon-chevron-down");
            $(this).data("target", "up");
            $(this).find(".text").text("展开选项");
        } else {
            $("#searchPanel .row").show(400);
            $(this).find(".glyphicon").removeClass("glyphicon-chevron-down").addClass("glyphicon-chevron-up");
            $(this).data("target", "down");
            $(this).find(".text").text("收起选项");
        }

    });

});<|endoftext|>


<commit_before>/*jslint browser: true */

define([
	'underscore',
	'jquery',
	'backbone',
	'module',
	'models/LinkCollection',
	'models/PublicationContributorCollection'
], function(_, $, Backbone, module, LinkCollection, PublicationContributorCollection) {
	"use strict";

	var model = Backbone.Model.extend({
		urlRoot : module.config().scriptRoot + '/manager/services/mppublications',

		/*
		 * The contributors attribute is a backbone model. This model contains attributes whose value
		 * is a PublicationContributorCollection.
		 */
		defaults : function() {
			return {
				links: new LinkCollection(),
				contributors : new Backbone.Model()
			}
		},

		parse : function(response, options) {
			var links = (this.has('links')) ? this.get('links') : new LinkCollection();
			var contributors = (this.has('contributors')) ? this.get('contributors') : new Backbone.Model();
			if (_.has(response, 'links') && response.links.length) {
				links.set(_.sortBy(response.links, 'rank'));
			}
			else {
				links.reset(null);
			}
			response.links = links;

			if (_.has(response, 'contributors')) {
				_.each(contributors.keys, function(contribType) {
					// Clear out collection if response doesn't contain the contribType
					if (!_.has(response.contributors, contribType)) {
						contributors.unset(contribType);
					}
				});
				_.each(response.contributors, function(contribs, contribType) {
					if (contributors.has(contribType)){
						contributors.get(contribType).set(contribs).sort();
					}
					else {
						contributors.set(contribType, new PublicationContributorCollection(contribs));
					}
				});

			}
			else {
				contributors.clear();
			}
			response.contributors = contributors;

			/*
				Need to remove interactions and text to work around an issue with some properties being returned that shouldn't be.
				When PUBSTWO-1272 has been resolved, this code can be removed.
		 	*/
			return _.omit(response, ['interactions', 'text']);
		},

		fetch : function(options) {
			var params = {
				data : {
					mimetype : 'json'
				}
			};
			if (_.isObject(options)) {
				_.extend(params, options);
			}
			return Backbone.Model.prototype.fetch.call(this, params);
		},

		/*
		 * @param {String} op - command that will be added to the url to perform an action on the pub
		 * @return {Jquery.Promise} - If the model is empty, resolves returning nothing. If not emtpy,
		 *     resolves with the received response if call succeeds, rejects with the validationErrors
		 *     array if the response contains validation errors, rejects with an error message if the failed response does
		 *     not contain validation errors.
		 */
		changeState : function(op) {
			var self = this;
			var deferred = $.Deferred();
			if (!this.isNew()) {
				$.ajax({
					url: this.urlRoot +  '/' + op,
					method : 'POST',
					headers : {
						'Accept' : 'application/json'
					},
					contentType : 'application/json',
					processData : false,
					data: '{"id" : ' + this.get('id') + '}',
					success : function(response) {
						deferred.resolve(response)
					},
					error : function(jqXHR, textStatus, error) {
						var resp = jqXHR.responseJSON;
						if (_.has(resp, 'validationErrors')
							&& _.isArray(resp.validationErrors)
							&& (resp.validationErrors.length > 0)) {
							self.set('validationErrors', resp.validationErrors);
							deferred.reject(resp);
						}
						else {
							deferred.reject('Unable to ' + op + ' the publication with error: ' + error);
						}
					}
				});
			}
			else {
				deferred.resolve();
			}
			return deferred.promise();
		},

		/*
		 * @return {Jquery.Promise} - resolves with the received response if the release succeeds, rejects with the validationErrors
		 *     array if the response contains validation errors, rejects with an error message if the failed response does
		 *     not contain validation errors.
		 */
		release : function() {
			return this.changeState('release');
		},

		/*
		 * @return {Jquery.Promise} - resolves with the received response if publish succeeds, rejects with the validationErrors
		 *     array if the response contains validation errors, rejects with an error message if the failed response does
		 *     not contain validation errors.
		 */
		publish : function() {
			return this.changeState('publish');
		},

		save : function(attributes, options) {
			/* Don't send validationErrors to the server */
			this.unset('validationErrors');
			return Backbone.Model.prototype.save.apply(this, arguments);
		}
	});

	return model;
});
<commit_msg>Fixed error when sorting the contributors during parsing.<commit_after>/*jslint browser: true */

define([
	'underscore',
	'jquery',
	'backbone',
	'module',
	'models/LinkCollection',
	'models/PublicationContributorCollection'
], function(_, $, Backbone, module, LinkCollection, PublicationContributorCollection) {
	"use strict";

	var model = Backbone.Model.extend({
		urlRoot : module.config().scriptRoot + '/manager/services/mppublications',

		/*
		 * The contributors attribute is a backbone model. This model contains attributes whose value
		 * is a PublicationContributorCollection.
		 */
		defaults : function() {
			return {
				links: new LinkCollection(),
				contributors : new Backbone.Model()
			}
		},

		parse : function(response, options) {
			var links = (this.has('links')) ? this.get('links') : new LinkCollection();
			var contributors = (this.has('contributors')) ? this.get('contributors') : new Backbone.Model();
			if (_.has(response, 'links') && response.links.length) {
				links.set(_.sortBy(response.links, 'rank'));
			}
			else {
				links.reset(null);
			}
			response.links = links;

			if (_.has(response, 'contributors')) {
				_.each(contributors.keys, function(contribType) {
					// Clear out collection if response doesn't contain the contribType
					if (!_.has(response.contributors, contribType)) {
						contributors.unset(contribType);
					}
				});
				_.each(response.contributors, function(contribs, contribType) {
					if (contributors.has(contribType)){
						var collection = contributors.get(contribType);
						collection.set(contribs);
						collection.sort();
					}
					else {
						contributors.set(contribType, new PublicationContributorCollection(contribs));
					}
				});

			}
			else {
				contributors.clear();
			}
			response.contributors = contributors;

			/*
				Need to remove interactions and text to work around an issue with some properties being returned that shouldn't be.
				When PUBSTWO-1272 has been resolved, this code can be removed.
		 	*/
			return _.omit(response, ['interactions', 'text']);
		},

		fetch : function(options) {
			var params = {
				data : {
					mimetype : 'json'
				}
			};
			if (_.isObject(options)) {
				_.extend(params, options);
			}
			return Backbone.Model.prototype.fetch.call(this, params);
		},

		/*
		 * @param {String} op - command that will be added to the url to perform an action on the pub
		 * @return {Jquery.Promise} - If the model is empty, resolves returning nothing. If not emtpy,
		 *     resolves with the received response if call succeeds, rejects with the validationErrors
		 *     array if the response contains validation errors, rejects with an error message if the failed response does
		 *     not contain validation errors.
		 */
		changeState : function(op) {
			var self = this;
			var deferred = $.Deferred();
			if (!this.isNew()) {
				$.ajax({
					url: this.urlRoot +  '/' + op,
					method : 'POST',
					headers : {
						'Accept' : 'application/json'
					},
					contentType : 'application/json',
					processData : false,
					data: '{"id" : ' + this.get('id') + '}',
					success : function(response) {
						deferred.resolve(response)
					},
					error : function(jqXHR, textStatus, error) {
						var resp = jqXHR.responseJSON;
						if (_.has(resp, 'validationErrors')
							&& _.isArray(resp.validationErrors)
							&& (resp.validationErrors.length > 0)) {
							self.set('validationErrors', resp.validationErrors);
							deferred.reject(resp);
						}
						else {
							deferred.reject('Unable to ' + op + ' the publication with error: ' + error);
						}
					}
				});
			}
			else {
				deferred.resolve();
			}
			return deferred.promise();
		},

		/*
		 * @return {Jquery.Promise} - resolves with the received response if the release succeeds, rejects with the validationErrors
		 *     array if the response contains validation errors, rejects with an error message if the failed response does
		 *     not contain validation errors.
		 */
		release : function() {
			return this.changeState('release');
		},

		/*
		 * @return {Jquery.Promise} - resolves with the received response if publish succeeds, rejects with the validationErrors
		 *     array if the response contains validation errors, rejects with an error message if the failed response does
		 *     not contain validation errors.
		 */
		publish : function() {
			return this.changeState('publish');
		},

		save : function(attributes, options) {
			/* Don't send validationErrors to the server */
			this.unset('validationErrors');
			return Backbone.Model.prototype.save.apply(this, arguments);
		}
	});

	return model;
});
<|endoftext|>


<commit_before>var chartOptions = {
	chartArea: {
		width: '100%',
		height: '100%',
		top: 75,
		right: 15,
		left: 75,
		bottom: 100
	},
	colors: ['#a11'],
	curveType: 'function',
	height: 600,
	hAxis: {
		textStyle: {
			fontSize: 12
		},
		slantedText: false,
		maxAlternation: 1
	},
	interpolateNulls: false,
	legend: {
		position: 'none',
	},
	vAxis: {
		minValue: 0,
		textStyle: {
			fontSize: 12
		},
		gridlines: {
			count: 11
		},
		minorGridlines: {
			count: 1
		},
		titleTextStyle: {
			fontSize: 14,
			italic: false
		}
	},
	pointShape: 'diamond',
	pointsVisible: true
}

function HistoryCtrl($scope, $http, $routeParams) {
	routeParams = $routeParams.params.split('|');

	var params = {
		component: routeParams[0],
		testCase: routeParams[1],
		metric: routeParams[2]
	};

	$scope.title = params.component + ' : ' + params.testCase;

	$http.get('api/v1/timeline', {params: params}).then(function(response) {
		var chartData = new google.visualization.DataTable();
		chartData.addColumn('string');
		chartData.addColumn('number');
		chartData.addRows(response.data);

		var div = document.createElement('div');
		div.id = 'history';
		$('#charts').append(div);

		chartOptions.title = params.metric;

		var lineChart = new google.visualization.LineChart(document.getElementById(div.id));
		lineChart.draw(chartData, chartOptions);
	});

	$http.get('api/v1/history', {params: params}).then(function(response) {
		$scope.history = response.data;
	});
}
<commit_msg>Decrease size of data points<commit_after>var chartOptions = {
	chartArea: {
		width: '100%',
		height: '100%',
		top: 75,
		right: 15,
		left: 75,
		bottom: 100
	},
	colors: ['#a11'],
	curveType: 'function',
	height: 600,
	hAxis: {
		textStyle: {
			fontSize: 12
		},
		slantedText: false,
		maxAlternation: 1
	},
	interpolateNulls: false,
	legend: {
		position: 'none',
	},
	vAxis: {
		minValue: 0,
		textStyle: {
			fontSize: 12
		},
		gridlines: {
			count: 11
		},
		minorGridlines: {
			count: 1
		},
		titleTextStyle: {
			fontSize: 14,
			italic: false
		}
	},
	pointShape: 'diamond',
	pointSize: 4,
	pointsVisible: true
}

function HistoryCtrl($scope, $http, $routeParams) {
	routeParams = $routeParams.params.split('|');

	var params = {
		component: routeParams[0],
		testCase: routeParams[1],
		metric: routeParams[2]
	};

	$scope.title = params.component + ' : ' + params.testCase;

	$http.get('api/v1/timeline', {params: params}).then(function(response) {
		var chartData = new google.visualization.DataTable();
		chartData.addColumn('string');
		chartData.addColumn('number');
		chartData.addRows(response.data);

		var div = document.createElement('div');
		div.id = 'history';
		$('#charts').append(div);

		chartOptions.title = params.metric;

		var lineChart = new google.visualization.LineChart(document.getElementById(div.id));
		lineChart.draw(chartData, chartOptions);
	});

	$http.get('api/v1/history', {params: params}).then(function(response) {
		$scope.history = response.data;
	});
}
<|endoftext|>


<commit_before>// ==========================================================================
//                        DG.ScatterPlotModel
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

sc_require('components/graph/plots/plot_model');
sc_require('components/graph/plots/numeric_plot_model_mixin');

/** @class  DG.ScatterPlotModel

  @extends DG.PlotModel
*/
DG.ScatterPlotModel = DG.PlotModel.extend( DG.NumericPlotModelMixin,
/** @scope DG.ScatterPlotModel.prototype */
{
  /**
    @property { DG.MovableLineModel }
  */
  movableLine: null,

  /**
    @property { Boolean, read only }
  */
  isMovableLineVisible: function() {
    return !SC.none( this.movableLine) && this.movableLine.get('isVisible');
  }.property('movableLine.isVisible'),

  /**
    @property { Boolean, read only }
  */
  isInterceptLocked: function() {
    return !SC.none( this.movableLine) && this.movableLine.get('isInterceptLocked');
  }.property('movableLine.isInterceptLocked'),

  /**
    @property { Boolean }
  */
  areSquaresVisible: false,

  /**
   * Used for notification
   * @property{}
   */
  squares: null,

  /**
   * Used for notification
   */
  lineDidChange: function() {
    this.notifyPropertyChange('squares');
  }.observes('.movableLine.slope', '.movableLine.intercept'),

  /**
   * Utility function to create a movable line when needed
   */
  createMovableLine: function() {
    if( SC.none( this.movableLine)) {
      this.beginPropertyChanges();
        this.set('movableLine', DG.MovableLineModel.create());
        this.movableLine.recomputeSlopeAndIntercept( this.get('xAxis'), this.get('yAxis'));
      this.endPropertyChanges();
    }
  },

  /**
    If we need to make a movable line, do so. In any event toggle its visibility.
  */
  toggleMovableLine: function() {
    var this_ = this;

    function toggle() {
      if( SC.none( this_.movableLine)) {
        this_.createMovableLine(); // Default is to be visible
      }
      else {
        this_.movableLine.recomputeSlopeAndInterceptIfNeeded( this_.get('xAxis'), this_.get('yAxis'));
        this_.movableLine.set('isVisible', !this_.movableLine.get('isVisible'));
      }
    }

    var willShow = !this.movableLine || !this.movableLine.get('isVisible');
    DG.UndoHistory.execute(DG.Command.create({
      name: "graph.toggleMovableLine",
      undoString: (willShow ? 'DG.Undo.graph.showMovableLine' : 'DG.Undo.graph.hideMovableLine'),
      redoString: (willShow ? 'DG.Redo.graph.showMovableLine' : 'DG.Redo.graph.hideMovableLine'),
      log: "toggleMovableLine: %@".fmt(willShow ? "show" : "hide"),
      execute: function() {
        toggle();
      },
      undo: function() {
        toggle();
      }
    }));
  },

  /**
    If we need to make a movable line, do so. In any event toggle whether its intercept is locked.
  */
  toggleInterceptLocked: function() {
    var this_ = this;

    function toggle() {
      if( SC.none( this_.movableLine)) {
        this_.createMovableLine(); // Default is to be unlocked
      }
      else {
        this_.movableLine.toggleInterceptLocked();
        this_.movableLine.recomputeSlopeAndInterceptIfNeeded( this_.get('xAxis'), this_.get('yAxis'));
      }
    }

    var willLock = !this.movableLine || !this.movableLine.get('isInterceptLocked');
    DG.UndoHistory.execute(DG.Command.create({
      name: "graph.toggleLockIntercept",
      undoString: (willLock ? 'DG.Undo.graph.lockIntercept' : 'DG.Undo.graph.unlockIntercept'),
      redoString: (willLock ? 'DG.Redo.graph.lockIntercept' : 'DG.Redo.graph.unlockIntercept'),
      log: "lockIntercept: %@".fmt(willLock),
      execute: function() {
        this._undoData = this_.movableLine.createStorage();
        toggle();
      },
      undo: function() {
        this_.movableLine.restoreStorage(this._undoData);
      }
    }));
  },

  /**
    If we need to make a plotted function, do so. In any event toggle its visibility.
  */
  togglePlotFunction: function() {
    var this_ = this;

    function toggle() {
      this_.toggleAdornmentVisibility('plottedFunction', 'togglePlotFunction');
      if( this_.isAdornmentVisible('plottedFunction')) {
        var plottedFunction = this_.getAdornmentModel('plottedFunction');
        if( plottedFunction)
          plottedFunction.set('dataConfiguration', this_.get('dataConfiguration'));
      }
    }

    var willShow = !this.isAdornmentVisible('plottedFunction');
    DG.UndoHistory.execute(DG.Command.create({
      name: "graph.togglePlotFunction",
      undoString: (willShow ? 'DG.Undo.graph.showPlotFunction' : 'DG.Undo.graph.hidePlotFunction'),
      redoString: (willShow ? 'DG.Redo.graph.showPlotFunction' : 'DG.Redo.graph.hidePlotFunction'),
      log: "togglePlotFunction: %@".fmt(willShow ? "show" : "hide"),
      execute: function() {
        toggle();
      },
      undo: function() {
        toggle();
      }
    }));
  },

  /**
    If we need to make a connecting line, do so. In any event toggle its visibility.
  */
  toggleConnectingLine: function() {
    var this_ = this;

    function toggle() {
      var tAdornModel = this_.toggleAdornmentVisibility('connectingLine', 'toggleConnectingLine');
      if( tAdornModel && tAdornModel.get('isVisible'))
        tAdornModel.recomputeValue(); // initialize
    }

    var willShow = !this.isAdornmentVisible('connectingLine');
    DG.UndoHistory.execute(DG.Command.create({
      name: "graph.toggleConnectingLine",
      undoString: (willShow ? 'DG.Undo.graph.showConnectingLine' : 'DG.Undo.graph.hideConnectingLine'),
      redoString: (willShow ? 'DG.Redo.graph.showConnectingLine' : 'DG.Redo.graph.hideConnectingLine'),
      log: "toggleConnectingLine: %@".fmt(willShow ? "show" : "hide"),
      execute: function() {
        toggle();
      },
      undo: function() {
        toggle();
      }
    }));
  },

  /**
    Convenience method for toggling Boolean property
  */
  toggleShowSquares: function() {
    var this_ = this;

    function toggle() {
      this_.set('areSquaresVisible', !this_.get('areSquaresVisible'));
    }

    var willShow = !this.get('areSquaresVisible');
    DG.UndoHistory.execute(DG.Command.create({
      name: "graph.toggleShowSquares",
      undoString: (willShow ? 'DG.Undo.graph.showSquares' : 'DG.Undo.graph.hideSquares'),
      redoString: (willShow ? 'DG.Redo.graph.showSquares' : 'DG.Redo.graph.hideSquares'),
      log: "toggleShowSquares: %@".fmt(willShow ? "show" : "hide"),
      execute: function() {
        toggle();
      },
      undo: function() {
        toggle();
      }
    }));
  },

  handleDataConfigurationChange: function() {
    sc_super();
    this.rescaleAxesFromData( true, /* allow scale shrinkage */
                              true /* do animation */);

    var adornmentModel = this.getAdornmentModel('connectingLine');
    if( adornmentModel) {
      adornmentModel.setComputingNeeded();  // invalidate if axis model/attribute change
    }
  },

  /**
    Each axis should rescale based on the values to be plotted with it.
    @param{Boolean} Default is false
    @param{Boolean} Default is true
    @param{Boolean} Default is false
  */
  rescaleAxesFromData: function( iAllowScaleShrinkage, iAnimatePoints, iLogIt, isUserAction) {
    if( iAnimatePoints === undefined)
      iAnimatePoints = true;
    this.doRescaleAxesFromData( [DG.GraphTypes.EPlace.eX, DG.GraphTypes.EPlace.eY, DG.GraphTypes.EPlace.eY2],
                                iAllowScaleShrinkage, iAnimatePoints, isUserAction);
    if( iLogIt && !isUserAction)
      DG.logUser("rescaleScatterplot");
  },

  /**
    @param{ {x: {Number}, y: {Number} } }
    @param{Number}
  */
  dilate: function( iFixedPoint, iFactor) {
    this.doDilation( [DG.GraphTypes.EPlace.eX, DG.GraphTypes.EPlace.eY], iFixedPoint, iFactor);
  },

  checkboxDescriptions: function() {
    var this_ = this;
    return sc_super().concat([
      {
        title: 'DG.Inspector.graphConnectingLine',
        value: this_.isAdornmentVisible('connectingLine'),
        classNames: 'graph-connectingLine-check'.w(),
        valueDidChange: function () {
          this_.toggleConnectingLine();
        }.observes('value')
      },
      {
        title: 'DG.Inspector.graphMovableLine',
        value: this_.get('isMovableLineVisible'),
        classNames: 'graph-movableLine-check'.w(),
        valueDidChange: function () {
          this_.toggleMovableLine();
        }.observes('value')
      },
      {
        title: 'DG.Inspector.graphInterceptLocked',
        value: this_.get('isInterceptLocked'),
        classNames: 'graph-interceptLocked-check'.w(),
        valueDidChange: function () {
          this_.toggleInterceptLocked();
        }.observes('value')
      },
      {
        title: 'DG.Inspector.graphSquares',
        value: this_.get('areSquaresVisible'),
        classNames: 'graph-squares-check'.w(),
        valueDidChange: function () {
          this_.toggleShowSquares();
        }.observes('value')
      },
      {
        title: 'DG.Inspector.graphPlottedFunction',
        value: this_.isAdornmentVisible('plottedFunction'),
        classNames: 'graph-plottedFunction-check'.w(),
        valueDidChange: function () {
          this_.togglePlotFunction();
        }.observes('value')
      }
    ]);
  }.property(),

  /**
   * @return { Object } with properties specific to a given subclass
   */
  createStorage: function() {
    var tStorage = sc_super(),
        tMovableLine = this.get('movableLine');
    if( !SC.none( tMovableLine))
      tStorage.movableLineStorage = tMovableLine.createStorage();
    if( this.get( 'areSquaresVisible'))
      tStorage.areSquaresVisible = true;

    return tStorage;
  },

  /**
   * @param { Object } with properties specific to a given subclass
   */
  restoreStorage: function( iStorage) {

    /*  Older documents stored adornments individually in the plot model
     *  that used them, e.g. movable lines and function plots were stored
     *  here with the scatter plot model. In newer documents, there is an
     *  'adornments' property in the base class (plot model) which stores
     *  all or most of the adornments. To preserve file format compatibility
     *  we move the locally stored storage objects into the base class
     *  'adornments' property where the base class will process them when
     *  we call sc_super().
     */
    this.moveAdornmentStorage( iStorage, 'movableLine', iStorage.movableLineStorage);
    this.moveAdornmentStorage( iStorage, 'plottedFunction', iStorage.plottedFunctionStorage);

    sc_super();

    if( iStorage.movableLineStorage) {
      if( SC.none( this.movableLine))
        this.createMovableLine();
      this.get('movableLine').restoreStorage( iStorage.movableLineStorage);
    }
    if( iStorage.areSquaresVisible)
      this.toggleShowSquares();

    // Legacy document support
    if( iStorage.plottedFunctionStorage) {
      if( SC.none( this.plottedFunction))
        this.set('plottedFunction', DG.PlottedFunctionModel.create());
      this.get('plottedFunction').restoreStorage( iStorage.plottedFunctionStorage);
    }
  },

  onRescaleIsComplete: function() {
    if( !SC.none( this.movableLine))
      this.movableLine.recomputeSlopeAndInterceptIfNeeded( this.get('xAxis'), this.get('yAxis'));
  },

  /**
   * Get an array of non-missing case counts in each axis cell.
   * Also cell index on primary and secondary axis, with primary axis as major axis.
   * @return {Array} [{count, primaryCell, secondaryCell},...] (all values are integers 0+).
   */
  getCellCaseCounts: function() {
    var tCases = this.get('cases'),
        tXVarID = this.get('xVarID'),
        tYVarID = this.get('yVarID'),
        tCount = 0,
        tValueArray = [];

    if( !( tXVarID && tYVarID )) {
      return tValueArray; // too early to recompute, caller must try again later.
    }

    // compute count and percent cases in each cell, excluding missing values
    tCases.forEach( function( iCase, iIndex ) {
      var tXVal = iCase.getNumValue( tXVarID),
          tYVal = iCase.getNumValue( tYVarID);
      if( isFinite( tXVal) && isFinite( tYVal)) ++tCount;
    });

    // initialize the values for the single 'cell' of the scatterplot
    tValueArray.push({
        count: tCount,
        primaryCell: 0,
        secondaryCell: 0
      });
    return tValueArray;
  }

});

<commit_msg>[Fixes #110498988] The 'lock intercept at zero' checkbox now observes the plot's 'isMovableLineVisible' property and redisplays when it changes to show correct 'isEnabled' state.<commit_after>// ==========================================================================
//                        DG.ScatterPlotModel
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

sc_require('components/graph/plots/plot_model');
sc_require('components/graph/plots/numeric_plot_model_mixin');

/** @class  DG.ScatterPlotModel

 @extends DG.PlotModel
 */
DG.ScatterPlotModel = DG.PlotModel.extend(DG.NumericPlotModelMixin,
    /** @scope DG.ScatterPlotModel.prototype */
    {
      /**
       @property { DG.MovableLineModel }
       */
      movableLine: null,

      /**
       @property { Boolean, read only }
       */
      isMovableLineVisible: function () {
        return !SC.none(this.movableLine) && this.movableLine.get('isVisible');
      }.property('movableLine.isVisible'),

      /**
       @property { Boolean, read only }
       */
      isInterceptLocked: function () {
        return !SC.none(this.movableLine) && this.movableLine.get('isInterceptLocked');
      }.property('movableLine.isInterceptLocked'),

      /**
       @property { Boolean }
       */
      areSquaresVisible: false,

      /**
       * Used for notification
       * @property{}
       */
      squares: null,

      /**
       * Used for notification
       */
      lineDidChange: function () {
        this.notifyPropertyChange('squares');
      }.observes('.movableLine.slope', '.movableLine.intercept'),

      /**
       * Utility function to create a movable line when needed
       */
      createMovableLine: function () {
        if (SC.none(this.movableLine)) {
          this.beginPropertyChanges();
          this.set('movableLine', DG.MovableLineModel.create());
          this.movableLine.recomputeSlopeAndIntercept(this.get('xAxis'), this.get('yAxis'));
          this.endPropertyChanges();
        }
      },

      /**
       If we need to make a movable line, do so. In any event toggle its visibility.
       */
      toggleMovableLine: function () {
        var this_ = this;

        function toggle() {
          if (SC.none(this_.movableLine)) {
            this_.createMovableLine(); // Default is to be visible
          }
          else {
            this_.movableLine.recomputeSlopeAndInterceptIfNeeded(this_.get('xAxis'), this_.get('yAxis'));
            this_.movableLine.set('isVisible', !this_.movableLine.get('isVisible'));
          }
        }

        var willShow = !this.movableLine || !this.movableLine.get('isVisible');
        DG.UndoHistory.execute(DG.Command.create({
          name: "graph.toggleMovableLine",
          undoString: (willShow ? 'DG.Undo.graph.showMovableLine' : 'DG.Undo.graph.hideMovableLine'),
          redoString: (willShow ? 'DG.Redo.graph.showMovableLine' : 'DG.Redo.graph.hideMovableLine'),
          log: "toggleMovableLine: %@".fmt(willShow ? "show" : "hide"),
          execute: function () {
            toggle();
          },
          undo: function () {
            toggle();
          }
        }));
      },

      /**
       If we need to make a movable line, do so. In any event toggle whether its intercept is locked.
       */
      toggleInterceptLocked: function () {
        var this_ = this;

        function toggle() {
          if (SC.none(this_.movableLine)) {
            this_.createMovableLine(); // Default is to be unlocked
          }
          else {
            this_.movableLine.toggleInterceptLocked();
            this_.movableLine.recomputeSlopeAndInterceptIfNeeded(this_.get('xAxis'), this_.get('yAxis'));
          }
        }

        var willLock = !this.movableLine || !this.movableLine.get('isInterceptLocked');
        DG.UndoHistory.execute(DG.Command.create({
          name: "graph.toggleLockIntercept",
          undoString: (willLock ? 'DG.Undo.graph.lockIntercept' : 'DG.Undo.graph.unlockIntercept'),
          redoString: (willLock ? 'DG.Redo.graph.lockIntercept' : 'DG.Redo.graph.unlockIntercept'),
          log: "lockIntercept: %@".fmt(willLock),
          execute: function () {
            this._undoData = this_.movableLine.createStorage();
            toggle();
          },
          undo: function () {
            this_.movableLine.restoreStorage(this._undoData);
          }
        }));
      },

      /**
       If we need to make a plotted function, do so. In any event toggle its visibility.
       */
      togglePlotFunction: function () {
        var this_ = this;

        function toggle() {
          this_.toggleAdornmentVisibility('plottedFunction', 'togglePlotFunction');
          if (this_.isAdornmentVisible('plottedFunction')) {
            var plottedFunction = this_.getAdornmentModel('plottedFunction');
            if (plottedFunction)
              plottedFunction.set('dataConfiguration', this_.get('dataConfiguration'));
          }
        }

        var willShow = !this.isAdornmentVisible('plottedFunction');
        DG.UndoHistory.execute(DG.Command.create({
          name: "graph.togglePlotFunction",
          undoString: (willShow ? 'DG.Undo.graph.showPlotFunction' : 'DG.Undo.graph.hidePlotFunction'),
          redoString: (willShow ? 'DG.Redo.graph.showPlotFunction' : 'DG.Redo.graph.hidePlotFunction'),
          log: "togglePlotFunction: %@".fmt(willShow ? "show" : "hide"),
          execute: function () {
            toggle();
          },
          undo: function () {
            toggle();
          }
        }));
      },

      /**
       If we need to make a connecting line, do so. In any event toggle its visibility.
       */
      toggleConnectingLine: function () {
        var this_ = this;

        function toggle() {
          var tAdornModel = this_.toggleAdornmentVisibility('connectingLine', 'toggleConnectingLine');
          if (tAdornModel && tAdornModel.get('isVisible'))
            tAdornModel.recomputeValue(); // initialize
        }

        var willShow = !this.isAdornmentVisible('connectingLine');
        DG.UndoHistory.execute(DG.Command.create({
          name: "graph.toggleConnectingLine",
          undoString: (willShow ? 'DG.Undo.graph.showConnectingLine' : 'DG.Undo.graph.hideConnectingLine'),
          redoString: (willShow ? 'DG.Redo.graph.showConnectingLine' : 'DG.Redo.graph.hideConnectingLine'),
          log: "toggleConnectingLine: %@".fmt(willShow ? "show" : "hide"),
          execute: function () {
            toggle();
          },
          undo: function () {
            toggle();
          }
        }));
      },

      /**
       Convenience method for toggling Boolean property
       */
      toggleShowSquares: function () {
        var this_ = this;

        function toggle() {
          this_.set('areSquaresVisible', !this_.get('areSquaresVisible'));
        }

        var willShow = !this.get('areSquaresVisible');
        DG.UndoHistory.execute(DG.Command.create({
          name: "graph.toggleShowSquares",
          undoString: (willShow ? 'DG.Undo.graph.showSquares' : 'DG.Undo.graph.hideSquares'),
          redoString: (willShow ? 'DG.Redo.graph.showSquares' : 'DG.Redo.graph.hideSquares'),
          log: "toggleShowSquares: %@".fmt(willShow ? "show" : "hide"),
          execute: function () {
            toggle();
          },
          undo: function () {
            toggle();
          }
        }));
      },

      handleDataConfigurationChange: function () {
        sc_super();
        this.rescaleAxesFromData(true, /* allow scale shrinkage */
            true /* do animation */);

        var adornmentModel = this.getAdornmentModel('connectingLine');
        if (adornmentModel) {
          adornmentModel.setComputingNeeded();  // invalidate if axis model/attribute change
        }
      },

      /**
       Each axis should rescale based on the values to be plotted with it.
       @param{Boolean} Default is false
       @param{Boolean} Default is true
       @param{Boolean} Default is false
       */
      rescaleAxesFromData: function (iAllowScaleShrinkage, iAnimatePoints, iLogIt, isUserAction) {
        if (iAnimatePoints === undefined)
          iAnimatePoints = true;
        this.doRescaleAxesFromData([DG.GraphTypes.EPlace.eX, DG.GraphTypes.EPlace.eY, DG.GraphTypes.EPlace.eY2],
            iAllowScaleShrinkage, iAnimatePoints, isUserAction);
        if (iLogIt && !isUserAction)
          DG.logUser("rescaleScatterplot");
      },

      /**
       @param{ {x: {Number}, y: {Number} } }
       @param{Number}
       */
      dilate: function (iFixedPoint, iFactor) {
        this.doDilation([DG.GraphTypes.EPlace.eX, DG.GraphTypes.EPlace.eY], iFixedPoint, iFactor);
      },

      checkboxDescriptions: function () {
        var this_ = this;
        return sc_super().concat([
          {
            title: 'DG.Inspector.graphConnectingLine',
            value: this_.isAdornmentVisible('connectingLine'),
            classNames: 'graph-connectingLine-check'.w(),
            valueDidChange: function () {
              this_.toggleConnectingLine();
            }.observes('value')
          },
          {
            title: 'DG.Inspector.graphMovableLine',
            value: this_.get('isMovableLineVisible'),
            classNames: 'graph-movableLine-check'.w(),
            valueDidChange: function () {
              this_.toggleMovableLine();
            }.observes('value')
          },
          {
            title: 'DG.Inspector.graphInterceptLocked',
            value: this_.get('isInterceptLocked'),
            classNames: 'graph-interceptLocked-check'.w(),
            isEnabled: function () {
              return this_.get('isMovableLineVisible');
            }.property(),
            valueDidChange: function () {
              this_.toggleInterceptLocked();
            }.observes('value'),
            init: function() {
              sc_super();
              this_.addObserver('isMovableLineVisible', this, 'displayDidChange');
            },
            destroy: function() {
              this_.removeObserver('isMovableLineVisible', this, 'displayDidChange');
              sc_super();
            }
          },
          {
            title: 'DG.Inspector.graphSquares',
            value: this_.get('areSquaresVisible'),
            classNames: 'graph-squares-check'.w(),
            valueDidChange: function () {
              this_.toggleShowSquares();
            }.observes('value')
          },
          {
            title: 'DG.Inspector.graphPlottedFunction',
            value: this_.isAdornmentVisible('plottedFunction'),
            classNames: 'graph-plottedFunction-check'.w(),
            valueDidChange: function () {
              this_.togglePlotFunction();
            }.observes('value')
          }
        ]);
      }.property(),

      /**
       * @return { Object } with properties specific to a given subclass
       */
      createStorage: function () {
        var tStorage = sc_super(),
            tMovableLine = this.get('movableLine');
        if (!SC.none(tMovableLine))
          tStorage.movableLineStorage = tMovableLine.createStorage();
        if (this.get('areSquaresVisible'))
          tStorage.areSquaresVisible = true;

        return tStorage;
      },

      /**
       * @param { Object } with properties specific to a given subclass
       */
      restoreStorage: function (iStorage) {

        /*  Older documents stored adornments individually in the plot model
         *  that used them, e.g. movable lines and function plots were stored
         *  here with the scatter plot model. In newer documents, there is an
         *  'adornments' property in the base class (plot model) which stores
         *  all or most of the adornments. To preserve file format compatibility
         *  we move the locally stored storage objects into the base class
         *  'adornments' property where the base class will process them when
         *  we call sc_super().
         */
        this.moveAdornmentStorage(iStorage, 'movableLine', iStorage.movableLineStorage);
        this.moveAdornmentStorage(iStorage, 'plottedFunction', iStorage.plottedFunctionStorage);

        sc_super();

        if (iStorage.movableLineStorage) {
          if (SC.none(this.movableLine))
            this.createMovableLine();
          this.get('movableLine').restoreStorage(iStorage.movableLineStorage);
        }
        if (iStorage.areSquaresVisible)
          this.toggleShowSquares();

        // Legacy document support
        if (iStorage.plottedFunctionStorage) {
          if (SC.none(this.plottedFunction))
            this.set('plottedFunction', DG.PlottedFunctionModel.create());
          this.get('plottedFunction').restoreStorage(iStorage.plottedFunctionStorage);
        }
      },

      onRescaleIsComplete: function () {
        if (!SC.none(this.movableLine))
          this.movableLine.recomputeSlopeAndInterceptIfNeeded(this.get('xAxis'), this.get('yAxis'));
      },

      /**
       * Get an array of non-missing case counts in each axis cell.
       * Also cell index on primary and secondary axis, with primary axis as major axis.
       * @return {Array} [{count, primaryCell, secondaryCell},...] (all values are integers 0+).
       */
      getCellCaseCounts: function () {
        var tCases = this.get('cases'),
            tXVarID = this.get('xVarID'),
            tYVarID = this.get('yVarID'),
            tCount = 0,
            tValueArray = [];

        if (!( tXVarID && tYVarID )) {
          return tValueArray; // too early to recompute, caller must try again later.
        }

        // compute count and percent cases in each cell, excluding missing values
        tCases.forEach(function (iCase, iIndex) {
          var tXVal = iCase.getNumValue(tXVarID),
              tYVal = iCase.getNumValue(tYVarID);
          if (isFinite(tXVal) && isFinite(tYVal)) ++tCount;
        });

        // initialize the values for the single 'cell' of the scatterplot
        tValueArray.push({
          count: tCount,
          primaryCell: 0,
          secondaryCell: 0
        });
        return tValueArray;
      }

    });

<|endoftext|>


<commit_before>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 *  BookmarksDialog.js.js
 *
 *  Created by Julia Radzhabova on 15.02.2018
 *  Copyright (c) 2017 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'common/main/lib/util/utils',
    'common/main/lib/component/ListView',
    'common/main/lib/component/InputField',
    'common/main/lib/component/Button',
    'common/main/lib/component/RadioBox',
    'common/main/lib/view/AdvancedSettingsWindow'
], function () { 'use strict';

    DE.Views.BookmarksDialog = Common.Views.AdvancedSettingsWindow.extend(_.extend({
        options: {
            contentWidth: 300,
            height: 360
        },

        initialize : function(options) {
            var me = this;

            _.extend(this.options, {
                title: this.textTitle,
                template: [
                    '
',
                        '

',
                            '
',
                                '
',
                                    '
',
                                        '',
                                        '', me.textBookmarkName, '',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '

',
                                            '<button type="button" result="add" class="btn btn-text-default" id="bookmarks-btn-add" style="vertical-align: top;">', me.textAdd,'</button>',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '', me.textSort,'',
                                            '

',
                                            '

',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                        '

',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '<button type="button" class="btn btn-text-default" id="bookmarks-btn-goto" style="margin-right: 10px;">', me.textGoto,'</button>',
                                            '<button type="button" class="btn btn-text-default" id="bookmarks-btn-delete" style="">', me.textDelete,'</button>',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '

',
                                        '	',
                                    '
',
                                '
',
                            '

',
                        '
',
                    '
',
                    '
',
                    '<button class="btn normal dlg-btn" result="cancel" style="width: 86px;">' + me.textClose + '</button>',
                    '
'
                ].join('')
            }, options);

            this.api        = options.api;
            this.handler    = options.handler;
            this.props      = options.props;

            Common.Views.AdvancedSettingsWindow.prototype.initialize.call(this, this.options);
        },

        render: function() {
            Common.Views.AdvancedSettingsWindow.prototype.render.call(this);
            var me = this;

            this.txtName = new Common.UI.InputField({
                el          : $('#bookmarks-txt-name'),
                allowBlank  : true,
                validateOnChange: true,
                validateOnBlur: false,
                style       : 'width: 195px;',
                value       : '',
                maxLength: 40
            }).on('changing', _.bind(this.onNameChanging, this));

            this.radioName = new Common.UI.RadioBox({
                el: $('#bookmarks-radio-name'),
                labelText: this.textName,
                name: 'asc-radio-bookmark-sort'
            });
            this.radioName.on('change', _.bind(this.onRadioSort, this));

            this.radioLocation = new Common.UI.RadioBox({
                el: $('#bookmarks-radio-location'),
                labelText: this.textLocation,
                name: 'asc-radio-bookmark-sort'
            });
            this.radioLocation.on('change', _.bind(this.onRadioSort, this));
            Common.Utils.InternalSettings.get("de-bookmarks-sort-location") ? this.radioLocation.setValue(true, true) : this.radioName.setValue(true, true);

            this.bookmarksList = new Common.UI.ListView({
                el: $('#bookmarks-list', this.$window),
                store: new Common.UI.DataViewStore(),
                itemTemplate: _.template('<div id="<%= id %>" class="list-item" style="pointer-events:none;"><%= value %>
')
            });
            this.bookmarksList.store.comparator = function(rec) {
                return (me.radioName.getValue() ? rec.get("value") : rec.get("location"));
            };
            this.bookmarksList.on('item:dblclick', _.bind(this.onDblClickBookmark, this));
            this.bookmarksList.on('entervalue', _.bind(this.onPrimary, this));
            this.bookmarksList.on('item:select', _.bind(this.onSelectBookmark, this));

            this.btnAdd = new Common.UI.Button({
                el: $('#bookmarks-btn-add'),
                disabled: true
            });
            this.$window.find('#bookmarks-btn-add').on('click', _.bind(this.onDlgBtnClick, this));

            this.btnGoto = new Common.UI.Button({
                el: $('#bookmarks-btn-goto'),
                disabled: true
            });
            this.btnGoto.on('click', _.bind(this.gotoBookmark, this));

            this.btnDelete = new Common.UI.Button({
                el: $('#bookmarks-btn-delete'),
                disabled: true
            });
            this.btnDelete.on('click', _.bind(this.deleteBookmark, this));

            this.chHidden = new Common.UI.CheckBox({
                el: $('#bookmarks-checkbox-hidden'),
                labelText: this.textHidden,
                value: Common.Utils.InternalSettings.get("de-bookmarks-hidden") || false
            });
            this.chHidden.on('change', _.bind(this.onChangeHidden, this));

            this.afterRender();
        },

        afterRender: function() {
            this._setDefaults(this.props);
        },

        show: function() {
            Common.Views.AdvancedSettingsWindow.prototype.show.apply(this, arguments);
        },

        close: function() {
            Common.Views.AdvancedSettingsWindow.prototype.close.apply(this, arguments);
            Common.Utils.InternalSettings.set("de-bookmarks-hidden", this.chHidden.getValue()=='checked');
            Common.Utils.InternalSettings.set("de-bookmarks-sort-location", this.radioLocation.getValue())
        },

        _setDefaults: function (props) {
            this.refreshBookmarks();
            this.bookmarksList.scrollToRecord(this.bookmarksList.selectByIndex(0));
        },

        getSettings: function () {
            return {};
        },

        onDlgBtnClick: function(event) {
            var state = (typeof(event) == 'object') ? event.currentTarget.attributes['result'].value : event;
            if (state == 'add') {
                this.props.asc_AddBookmark(this.txtName.getValue());
            }

            this.close();
        },

        onPrimary: function() {
            return true;
        },

        refreshBookmarks: function() {
            if (this.props) {
                var store = this.bookmarksList.store,
                    count = this.props.asc_GetCount(),
                    showHidden = this.chHidden.getValue()=='checked',
                    arr = [];
                for (var i=0; i<count; i++) {
                    var name = this.props.asc_GetName(i);
                    if (!this.props.asc_IsInternalUseBookmark(name) && (showHidden || !this.props.asc_IsHiddenBookmark(name))) {
                        var rec = new Common.UI.DataViewModel();
                        rec.set({
                            value: name,
                            location: i
                        });
                        arr.push(rec);
                    }
                }
                store.reset(arr, {silent: false});
            }
        },

        onSelectBookmark: function(listView, itemView, record) {
            var value = record.get('value');
            this.txtName.setValue(value);
            this.btnAdd.setDisabled(false);
            this.btnGoto.setDisabled(false);
            this.btnDelete.setDisabled(false);
        },

        gotoBookmark: function(btn, eOpts){
            var rec = this.bookmarksList.getSelectedRec();
            if (rec.length>0) {
                this.props.asc_GoToBookmark(rec[0].get('value'));
            }
        },

        onDblClickBookmark: function(listView, itemView, record) {
            this.props.asc_GoToBookmark(record.get('value'));
        },

        deleteBookmark: function(btn, eOpts){
            var rec = this.bookmarksList.getSelectedRec();
            if (rec.length>0) {
                this.props.asc_RemoveBookmark(rec[0].get('value'));
                var store = this.bookmarksList.store;
                var idx = _.indexOf(store.models, rec[0]);
                store.remove(rec[0]);
                this.txtName.setValue('');
                this.btnAdd.setDisabled(true);
                this.btnGoto.setDisabled(true);
                this.btnDelete.setDisabled(true);
            }
        },

        onRadioSort: function(field, newValue, eOpts) {
            if (newValue) {
                this.bookmarksList.store.sort();
                this.bookmarksList.onResetItems();
            }
        },

        onChangeHidden: function(field, newValue, oldValue, eOpts){
            this.refreshBookmarks();
        },

        onNameChanging: function (input, value) {
            var exist = this.props.asc_HaveBookmark(value);
            this.bookmarksList.deselectAll();
            this.btnAdd.setDisabled(!this.props.asc_CheckNewBookmarkName(value) && !exist);
            this.btnGoto.setDisabled(!exist);
            this.btnDelete.setDisabled(!exist);
        },

        textTitle:    'Bookmarks',
        textLocation: 'Location',
        textBookmarkName: 'Bookmark name',
        textSort: 'Sort by',
        textName: 'Name',
        textAdd: 'Add',
        textGoto: 'Go to',
        textDelete: 'Delete',
        textClose: 'Close',
        textHidden: 'Hidden bookmarks'

    }, DE.Views.BookmarksDialog || {}))
});<commit_msg>[DE] Bookmarks: select existing bookmark in the list when typing new name<commit_after>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 *  BookmarksDialog.js.js
 *
 *  Created by Julia Radzhabova on 15.02.2018
 *  Copyright (c) 2017 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'common/main/lib/util/utils',
    'common/main/lib/component/ListView',
    'common/main/lib/component/InputField',
    'common/main/lib/component/Button',
    'common/main/lib/component/RadioBox',
    'common/main/lib/view/AdvancedSettingsWindow'
], function () { 'use strict';

    DE.Views.BookmarksDialog = Common.Views.AdvancedSettingsWindow.extend(_.extend({
        options: {
            contentWidth: 300,
            height: 360
        },

        initialize : function(options) {
            var me = this;

            _.extend(this.options, {
                title: this.textTitle,
                template: [
                    '
',
                        '

',
                            '
',
                                '
',
                                    '
',
                                        '',
                                        '', me.textBookmarkName, '',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '

',
                                            '<button type="button" result="add" class="btn btn-text-default" id="bookmarks-btn-add" style="vertical-align: top;">', me.textAdd,'</button>',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '', me.textSort,'',
                                            '

',
                                            '

',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                        '

',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '<button type="button" class="btn btn-text-default" id="bookmarks-btn-goto" style="margin-right: 10px;">', me.textGoto,'</button>',
                                            '<button type="button" class="btn btn-text-default" id="bookmarks-btn-delete" style="">', me.textDelete,'</button>',
                                        '	',
                                    '
',
                                    '
',
                                        '',
                                            '

',
                                        '	',
                                    '
',
                                '
',
                            '

',
                        '
',
                    '
',
                    '
',
                    '<button class="btn normal dlg-btn" result="cancel" style="width: 86px;">' + me.textClose + '</button>',
                    '
'
                ].join('')
            }, options);

            this.api        = options.api;
            this.handler    = options.handler;
            this.props      = options.props;

            Common.Views.AdvancedSettingsWindow.prototype.initialize.call(this, this.options);
        },

        render: function() {
            Common.Views.AdvancedSettingsWindow.prototype.render.call(this);
            var me = this;

            this.txtName = new Common.UI.InputField({
                el          : $('#bookmarks-txt-name'),
                allowBlank  : true,
                validateOnChange: true,
                validateOnBlur: false,
                style       : 'width: 195px;',
                value       : '',
                maxLength: 40
            }).on('changing', _.bind(this.onNameChanging, this));

            this.radioName = new Common.UI.RadioBox({
                el: $('#bookmarks-radio-name'),
                labelText: this.textName,
                name: 'asc-radio-bookmark-sort'
            });
            this.radioName.on('change', _.bind(this.onRadioSort, this));

            this.radioLocation = new Common.UI.RadioBox({
                el: $('#bookmarks-radio-location'),
                labelText: this.textLocation,
                name: 'asc-radio-bookmark-sort'
            });
            this.radioLocation.on('change', _.bind(this.onRadioSort, this));
            Common.Utils.InternalSettings.get("de-bookmarks-sort-location") ? this.radioLocation.setValue(true, true) : this.radioName.setValue(true, true);

            this.bookmarksList = new Common.UI.ListView({
                el: $('#bookmarks-list', this.$window),
                store: new Common.UI.DataViewStore(),
                itemTemplate: _.template('<div id="<%= id %>" class="list-item" style="pointer-events:none;"><%= value %>
')
            });
            this.bookmarksList.store.comparator = function(rec) {
                return (me.radioName.getValue() ? rec.get("value") : rec.get("location"));
            };
            this.bookmarksList.on('item:dblclick', _.bind(this.onDblClickBookmark, this));
            this.bookmarksList.on('entervalue', _.bind(this.onPrimary, this));
            this.bookmarksList.on('item:select', _.bind(this.onSelectBookmark, this));

            this.btnAdd = new Common.UI.Button({
                el: $('#bookmarks-btn-add'),
                disabled: true
            });
            this.$window.find('#bookmarks-btn-add').on('click', _.bind(this.onDlgBtnClick, this));

            this.btnGoto = new Common.UI.Button({
                el: $('#bookmarks-btn-goto'),
                disabled: true
            });
            this.btnGoto.on('click', _.bind(this.gotoBookmark, this));

            this.btnDelete = new Common.UI.Button({
                el: $('#bookmarks-btn-delete'),
                disabled: true
            });
            this.btnDelete.on('click', _.bind(this.deleteBookmark, this));

            this.chHidden = new Common.UI.CheckBox({
                el: $('#bookmarks-checkbox-hidden'),
                labelText: this.textHidden,
                value: Common.Utils.InternalSettings.get("de-bookmarks-hidden") || false
            });
            this.chHidden.on('change', _.bind(this.onChangeHidden, this));

            this.afterRender();
        },

        afterRender: function() {
            this._setDefaults(this.props);
        },

        show: function() {
            Common.Views.AdvancedSettingsWindow.prototype.show.apply(this, arguments);
        },

        close: function() {
            Common.Views.AdvancedSettingsWindow.prototype.close.apply(this, arguments);
            Common.Utils.InternalSettings.set("de-bookmarks-hidden", this.chHidden.getValue()=='checked');
            Common.Utils.InternalSettings.set("de-bookmarks-sort-location", this.radioLocation.getValue())
        },

        _setDefaults: function (props) {
            this.refreshBookmarks();
            this.bookmarksList.scrollToRecord(this.bookmarksList.selectByIndex(0));
        },

        getSettings: function () {
            return {};
        },

        onDlgBtnClick: function(event) {
            var state = (typeof(event) == 'object') ? event.currentTarget.attributes['result'].value : event;
            if (state == 'add') {
                this.props.asc_AddBookmark(this.txtName.getValue());
            }

            this.close();
        },

        onPrimary: function() {
            return true;
        },

        refreshBookmarks: function() {
            if (this.props) {
                var store = this.bookmarksList.store,
                    count = this.props.asc_GetCount(),
                    showHidden = this.chHidden.getValue()=='checked',
                    arr = [];
                for (var i=0; i<count; i++) {
                    var name = this.props.asc_GetName(i);
                    if (!this.props.asc_IsInternalUseBookmark(name) && (showHidden || !this.props.asc_IsHiddenBookmark(name))) {
                        var rec = new Common.UI.DataViewModel();
                        rec.set({
                            value: name,
                            location: i
                        });
                        arr.push(rec);
                    }
                }
                store.reset(arr, {silent: false});
            }
        },

        onSelectBookmark: function(listView, itemView, record) {
            var value = record.get('value');
            this.txtName.setValue(value);
            this.btnAdd.setDisabled(false);
            this.btnGoto.setDisabled(false);
            this.btnDelete.setDisabled(false);
        },

        gotoBookmark: function(btn, eOpts){
            var rec = this.bookmarksList.getSelectedRec();
            if (rec.length>0) {
                this.props.asc_GoToBookmark(rec[0].get('value'));
            }
        },

        onDblClickBookmark: function(listView, itemView, record) {
            this.props.asc_GoToBookmark(record.get('value'));
        },

        deleteBookmark: function(btn, eOpts){
            var rec = this.bookmarksList.getSelectedRec();
            if (rec.length>0) {
                this.props.asc_RemoveBookmark(rec[0].get('value'));
                var store = this.bookmarksList.store;
                var idx = _.indexOf(store.models, rec[0]);
                store.remove(rec[0]);
                this.txtName.setValue('');
                this.btnAdd.setDisabled(true);
                this.btnGoto.setDisabled(true);
                this.btnDelete.setDisabled(true);
            }
        },

        onRadioSort: function(field, newValue, eOpts) {
            if (newValue) {
                this.bookmarksList.store.sort();
                this.bookmarksList.onResetItems();
            }
        },

        onChangeHidden: function(field, newValue, oldValue, eOpts){
            this.refreshBookmarks();
        },

        onNameChanging: function (input, value) {
            var exist = this.props.asc_HaveBookmark(value);
            if (exist)
                this.bookmarksList.selectRecord(this.bookmarksList.store.findWhere({value: value}));
            else
                this.bookmarksList.deselectAll();
            this.btnAdd.setDisabled(!this.props.asc_CheckNewBookmarkName(value) && !exist);
            this.btnGoto.setDisabled(!exist);
            this.btnDelete.setDisabled(!exist);
        },

        textTitle:    'Bookmarks',
        textLocation: 'Location',
        textBookmarkName: 'Bookmark name',
        textSort: 'Sort by',
        textName: 'Name',
        textAdd: 'Add',
        textGoto: 'Go to',
        textDelete: 'Delete',
        textClose: 'Close',
        textHidden: 'Hidden bookmarks'

    }, DE.Views.BookmarksDialog || {}))
});<|endoftext|>


<commit_before>// ==UserScript==
// @name         JVC Colorful Followers
// @version      1.1
// @description  Colore les pseudos qui vous suivent et que vous suivez
// @author       NocturneX
// @icon         https://image.noelshack.com/fichiers/2019/28/6/1563019174-1406836919770.gif
// @match        *://www.jeuxvideo.com/forums/0-*
// @match        *://www.jeuxvideo.com/forums/1-*
// @match        *://www.jeuxvideo.com/forums/42-*
// @match        *://www.jeuxvideo.com/recherche/forums/0-*
// @grant        GM_addStyle
// ==/UserScript==

(async function() {
    'use strict';

    const useDarkJVC = window.getComputedStyle(document.querySelector(".jv-header-top"), null).getPropertyValue("background-color") == "rgb(41, 41, 41)"

    if(!useDarkJVC) {

        // Style pour JVC sans le thème DarkJVC
        GM_addStyle(
            `.colorful-abonne { color: #0b25e1 !important; }` +
            `.colorful-abonnement { color: #e97c0b !important; }` +
            `.colorful-abonne-et-abonnement { color: #293fe1 !important; text-shadow: 0px 0px 4px #01ffad; padding: 0 2px; }`
        )

    } else {

        // Style pour JVC avec le thème DarkJVC
        GM_addStyle(
            `.colorful-abonne { color: #71b0dc !important; }` +
            `.colorful-abonnement { color: #c68139 !important; }` +
            `.colorful-abonne-et-abonnement { color: #e7e7e7 !important; text-shadow: 0px 0px 4px #01ffad; padding: 0 2px; }`
        )

    }

    const currentPseudo = document.querySelector(".account-pseudo").textContent.trim().toLowerCase()

    if(currentPseudo == "mon compte") {
        return
    }

    const pageType = function () {
        if(/jeuxvideo\.com\/forums\/(42|1)-/.test(document.location.href)) {
            return 1
        } else if(/jeuxvideo\.com\/forums\/0-/.test(document.location.href) || /jeuxvideo\.com\/recherche\/forums\/0-/.test(document.location.href)) {
            return 2
        }
        return 0
    }()

    const getAbonnes = async function (pseudo = currentPseudo) {
        const pseudoList = []
        let page = 1
        let nextPageExist = false
        do {
            const response = await fetch(`https://www.jeuxvideo.com/profil/${pseudo}?mode=abonne&page=${page}`)
            const html = (new DOMParser()).parseFromString(await response.text(), "text/html")
            nextPageExist = !!html.querySelector(".pagi-fin-actif")
            html.querySelectorAll(".fiche-abonne .pseudo a:first-child").forEach(a => pseudoList.push(a.textContent.trim().toLowerCase()))
            page++
        } while(nextPageExist)
        return pseudoList
    }

    const getAbonnements = async function (pseudo = currentPseudo) {
        const response = await fetch(`https://www.jeuxvideo.com/profil/${pseudo}?mode=abonnements`)
        const html = (new DOMParser()).parseFromString(await response.text(), "text/html")
        const pseudoList = []
        html.querySelectorAll(".back-abo-perso a").forEach(a => pseudoList.push(a.textContent.trim().toLowerCase()))
        return pseudoList
    }

    const getPseudoInPage = async function () {
        const pseudoList = []
        switch(pageType) {
            case 1: document.querySelectorAll(".bloc-message-forum .user-avatar-msg").forEach(img => pseudoList.push(img.alt.toLowerCase())); break
            case 2: document.querySelectorAll(".topic-list a.topic-author").forEach(a => pseudoList.push(a.textContent.trim().toLowerCase())); break
        }
        return pseudoList
    }

    const abonnes = await getAbonnes()
    const abonnements = await getAbonnements()
    const pseudoList = {}
    for(let pseudo of await getPseudoInPage()) {
        if(!pseudoList.hasOwnProperty(pseudo)) {
            pseudoList[pseudo] = 0b00
            if(abonnes.indexOf(pseudo) > -1) {
                pseudoList[pseudo] += 0b01
            }
            if(abonnements.indexOf(pseudo) > -1) {
                pseudoList[pseudo] += 0b10
            }
        }
    }

    for(let pseudo in pseudoList) {
        const value = pseudoList[pseudo]
        let className = null
        switch(value) {
            case 0b01: className = "colorful-abonne"; break
            case 0b10: className = "colorful-abonnement"; break
            case 0b11: className = "colorful-abonne-et-abonnement"; break
        }

        document
            .querySelectorAll(`a.text-user[href='http://www.jeuxvideo.com/profil/${pseudo}?mode=infos'], a.text-user[href='https://www.jeuxvideo.com/profil/${pseudo}?mode=infos']`)
            .forEach(a => className ? a.classList.add(className) : null)
    }

})();
<commit_msg>Changement des couleurs<commit_after>// ==UserScript==
// @name         JVC Colorful Followers
// @version      1.2
// @description  Colore les pseudos qui vous suivent et que vous suivez
// @author       NocturneX
// @icon         https://image.noelshack.com/fichiers/2019/28/6/1563019174-1406836919770.gif
// @match        *://www.jeuxvideo.com/forums/0-*
// @match        *://www.jeuxvideo.com/forums/1-*
// @match        *://www.jeuxvideo.com/forums/42-*
// @match        *://www.jeuxvideo.com/recherche/forums/0-*
// @grant        GM_addStyle
// ==/UserScript==

(async function() {
    'use strict';

    const useDarkJVC = window.getComputedStyle(document.querySelector(".jv-header-top"), null).getPropertyValue("background-color") == "rgb(41, 41, 41)"

    if(!useDarkJVC) {

        // Style pour JVC sans le thème DarkJVC
        GM_addStyle(
            `.colorful-abonne { color: #0b25e1 !important; }` +
            `.colorful-abonnement { color: #e97c0b !important; }` +
            `.colorful-abonne-et-abonnement { color: #ff00a5 !important; }`
        )

    } else {

        // Style pour JVC avec le thème DarkJVC
        GM_addStyle(
            `.colorful-abonne { color: #71b0dc !important; }` +
            `.colorful-abonnement { color: #c68139 !important; }` +
            `.colorful-abonne-et-abonnement { color: #eb39ac !important; }`
        )

    }

    const currentPseudo = document.querySelector(".account-pseudo").textContent.trim().toLowerCase()

    if(currentPseudo == "mon compte") {
        return
    }

    const pageType = function () {
        if(/jeuxvideo\.com\/forums\/(42|1)-/.test(document.location.href)) {
            return 1
        } else if(/jeuxvideo\.com\/forums\/0-/.test(document.location.href) || /jeuxvideo\.com\/recherche\/forums\/0-/.test(document.location.href)) {
            return 2
        }
        return 0
    }()

    const getAbonnes = async function (pseudo = currentPseudo) {
        const pseudoList = []
        let page = 1
        let nextPageExist = false
        do {
            const response = await fetch(`https://www.jeuxvideo.com/profil/${pseudo}?mode=abonne&page=${page}`)
            const html = (new DOMParser()).parseFromString(await response.text(), "text/html")
            nextPageExist = !!html.querySelector(".pagi-fin-actif")
            html.querySelectorAll(".fiche-abonne .pseudo a:first-child").forEach(a => pseudoList.push(a.textContent.trim().toLowerCase()))
            page++
        } while(nextPageExist)
        return pseudoList
    }

    const getAbonnements = async function (pseudo = currentPseudo) {
        const response = await fetch(`https://www.jeuxvideo.com/profil/${pseudo}?mode=abonnements`)
        const html = (new DOMParser()).parseFromString(await response.text(), "text/html")
        const pseudoList = []
        html.querySelectorAll(".back-abo-perso a").forEach(a => pseudoList.push(a.textContent.trim().toLowerCase()))
        return pseudoList
    }

    const getPseudoInPage = async function () {
        const pseudoList = []
        switch(pageType) {
            case 1: document.querySelectorAll(".bloc-message-forum .user-avatar-msg").forEach(img => pseudoList.push(img.alt.toLowerCase())); break
            case 2: document.querySelectorAll(".topic-list a.topic-author").forEach(a => pseudoList.push(a.textContent.trim().toLowerCase())); break
        }
        return pseudoList
    }

    const abonnes = await getAbonnes()
    const abonnements = await getAbonnements()
    const pseudoList = {}
    for(let pseudo of await getPseudoInPage()) {
        if(!pseudoList.hasOwnProperty(pseudo)) {
            pseudoList[pseudo] = 0b00
            if(abonnes.indexOf(pseudo) > -1) {
                pseudoList[pseudo] += 0b01
            }
            if(abonnements.indexOf(pseudo) > -1) {
                pseudoList[pseudo] += 0b10
            }
        }
    }

    for(let pseudo in pseudoList) {
        const value = pseudoList[pseudo]
        let className = null
        switch(value) {
            case 0b01: className = "colorful-abonne"; break
            case 0b10: className = "colorful-abonnement"; break
            case 0b11: className = "colorful-abonne-et-abonnement"; break
        }

        document
            .querySelectorAll(`a.text-user[href='http://www.jeuxvideo.com/profil/${pseudo}?mode=infos'], a.text-user[href='https://www.jeuxvideo.com/profil/${pseudo}?mode=infos']`)
            .forEach(a => className ? a.classList.add(className) : null)
    }

})();
<|endoftext|>


<commit_before>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require) {
    'use strict';

    var $ = require('jquery');
    var ModalView = require('modals/_modalView');
    var Util = require('util');
    var Localization = require('localization');

    var ModalAnalyseLaunches = ModalView.extend({

        template: 'tpl-modal-analyse-launches',
        className: 'modal-analyse-launches',
        events: {
            'click [data-js-analyze]': 'onAnalyze'
        },
        initialize: function (options) {
            this.render();
            $('[value="' + options.analyzerMode + '"]', this.$el).attr('checked', 'checked');
        },
        render: function () {
            var footerButtons = [
                {
                    btnText: Localization.ui.cancel,
                    btnClass: 'rp-btn-cancel',
                    label: 'data-js-cancel'
                },
                {
                    btnText: Localization.ui.analyse,
                    btnClass: 'rp-btn-submit',
                    label: 'data-js-analyze'
                }
            ];
            this.$el.html(Util.templates(this.template, { footerButtons: footerButtons }));
        },
        onKeySuccess: function () {
            $('[data-js-analyse]', this.$el).focus().trigger('click');
        },

        onAnalyze: function () {
            this.successClose({
                analyzerMode: $('input:checked', this.$el).val()
            });
        }
    });

    return ModalAnalyseLaunches;
});
<commit_msg>Modal Analyse launch hotkey fix.<commit_after>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require) {
    'use strict';

    var $ = require('jquery');
    var ModalView = require('modals/_modalView');
    var Util = require('util');
    var Localization = require('localization');

    var ModalAnalyseLaunches = ModalView.extend({

        template: 'tpl-modal-analyse-launches',
        className: 'modal-analyse-launches',
        events: {
            'click [data-js-analyze]': 'onAnalyze'
        },
        initialize: function (options) {
            this.render();
            $('[value="' + options.analyzerMode + '"]', this.$el).attr('checked', 'checked');
        },
        render: function () {
            var footerButtons = [
                {
                    btnText: Localization.ui.cancel,
                    btnClass: 'rp-btn-cancel',
                    label: 'data-js-cancel'
                },
                {
                    btnText: Localization.ui.analyse,
                    btnClass: 'rp-btn-submit',
                    label: 'data-js-analyze'
                }
            ];
            this.$el.html(Util.templates(this.template, { footerButtons: footerButtons }));
        },
        onKeySuccess: function () {
            $('[data-js-analyze]', this.$el).focus().trigger('click');
        },

        onAnalyze: function () {
            this.successClose({
                analyzerMode: $('input:checked', this.$el).val()
            });
        }
    });

    return ModalAnalyseLaunches;
});
<|endoftext|>