<commit_before>var expect = require('chai').expect
var actions = require('../lib/actions')
var _ = require('lodash')
var sinon = require('sinon')

describe('changeValue action', function () {
  it(`returns a dispatcher action with type "${actions.CHANGE_VALUE}"`, function () {
    var action = actions.changeValue('some.path', 'value')

    expect(action).to.eql({
      type: actions.CHANGE_VALUE,
      bunsenId: 'some.path',
      value: 'value'
    })
  })
})

describe('validate action', function () {
  var SCHEMA_WITH_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName']
  }
  var SCHEMA_WITH_OBJECT_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName'],
    default: {
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman'
    }
  }
  var SCHEMA_WITH_DEEP_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string',
                default: 'Bruce'
              },
              lastName: {
                type: 'string',
                default: 'Wayne'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      }
    },
    required: ['alias']
  }

  var SCHEMA_WITH_REFS = {
    type: 'object',
    properties: {
      hero: {
        type: 'object',
        '$ref': '#/definitions/superhero'
      }
    },
    required: ['hero'],
    definitions: {
      superhero: {
        type: 'object',
        properties: {
          firstName: {
            type: 'string',
            default: 'Bruce'
          },
          lastName: {
            type: 'string',
            default: 'Wayne'
          },
          alias: {
            type: 'string',
            title: 'Nickname',
            default: 'Batman'
          }
        }
      }
    }
  }

  var SCHEMA_WITH_NO_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string'
              },
              lastName: {
                type: 'string'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname'
      }
    }
  }

  var SCHEMA_WITH_ARRAY_DEFAULTS = {
    type: 'object',
    properties: {
      superheroes: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            firstName: {
              type: 'string',
              default: 'Bruce'
            },
            lastName: {
              type: 'string',
              default: 'Wayne'
            },
            alias: {
              type: 'string',
              title: 'Nickname',
              default: 'Batman'
            }
          }
        }
      }
    }
  }

  function getDefaultValue (path, initialValue, schema) {
    var thunk = actions.validate(path, initialValue, schema, [])
    var defaultValue = {}

    thunk(function (action) {
      _.assign(defaultValue, action.value)
    }, function () { return {} })

    return defaultValue
  }
  it('fills in defaults', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne',
      alias: 'Batman',
      onlyChild: true
    })
  })

  it('fills in defaults for specific values', function () {
    var defaultValue = getDefaultValue('someotherProp.name', {}, SCHEMA_WITH_DEEP_DEFAULTS)

    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne'
    })
  })

  it('handles defaults in deep objects', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEEP_DEFAULTS)
    expect(defaultValue).to.eql({
      someotherProp: {
        name: {
          firstName: 'Bruce',
          lastName: 'Wayne'
        }
      },
      alias: 'Batman'
    })
  })

  it('handles defaults for objects', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_OBJECT_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman',
      onlyChild: true
    })
  })

  it('handles defaults in refs', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_REFS)
    expect(defaultValue).to.eql({
      hero: {
        firstName: 'Bruce',
        lastName: 'Wayne',
        alias: 'Batman'
      }
    })
  })

  it('handles a schema with no defaults', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_NO_DEFAULTS)
    expect(defaultValue).to.eql({})
  })

  function getState () {
    return {
      get value () {
        return {}
      }
    }
  }

  it('resolves if no validators are given', function () {
    var schema = _.cloneDeep(SCHEMA_WITH_DEFAULTS)
    delete schema.required
    var thunk = actions.validate(null, {}, schema, [])
    thunk(function (action) {
      if (action.type === actions.VALIDATION_RESOLVED) {
        expect(action.errors).to.eql({})
      }
    }, getState)
  })

  describe('when value is the same', function () {
    var schema, state, spy

    beforeEach(function () {
      schema = _.cloneDeep(SCHEMA_WITH_NO_DEFAULTS)
      spy = sinon.spy()
      state = {
        value: {
          alias: 'Bob'
        }
      }
    })

    // NOTE: the full form value always re-triggers validation. Otherwise we get
    // ourselves into a state where defaults aren't applied.
    describe('check entire form for changes', function () {
      it('dispatches action', function () {
        var thunk = actions.validate(null, _.cloneDeep(state.value), schema, [])

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount, 'dispatches nothing').to.equal(1)
      })

      it('dispatches action when forceValidation is disabled', function () {
        var thunk = actions.validate(null, _.cloneDeep(state.value), schema, [], Promise.all, false)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount, 'dispatches nothing').to.equal(1)
      })

      it('dispatches action when forceValidation is enabled', function () {
        var thunk = actions.validate(null, _.cloneDeep(state.value), schema, [], Promise.all, true)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount, 'dispatches nothing').to.equal(1)
      })
    })

    describe('check property for changes', function () {
      it('does not dispatch action', function () {
        var thunk = actions.validate('alias', _.cloneDeep(state.value.alias), schema, [])

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount, 'dispatches nothing').to.equal(0)
      })

      it('does not dispatch action when forceValidation is disabled', function () {
        var thunk = actions.validate('alias', _.cloneDeep(state.value.alias), schema, [], Promise.all, false)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount, 'dispatches nothing').to.equal(0)
      })

      it('dispatches action when forceValidation is enabled', function () {
        var thunk = actions.validate('alias', _.cloneDeep(state.value.alias), schema, [], Promise.all, true)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount, 'dispatches nothing').to.equal(1)
      })
    })
  })

  it('handles defaults for new array elements', function () {
    var defaultValue = getDefaultValue('superheroes.0', {}, SCHEMA_WITH_ARRAY_DEFAULTS)

    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne',
      alias: 'Batman'
    })
  })
})
<commit_msg>Remove useless expect descriptions<commit_after>var expect = require('chai').expect
var actions = require('../lib/actions')
var _ = require('lodash')
var sinon = require('sinon')

describe('changeValue action', function () {
  it(`returns a dispatcher action with type "${actions.CHANGE_VALUE}"`, function () {
    var action = actions.changeValue('some.path', 'value')

    expect(action).to.eql({
      type: actions.CHANGE_VALUE,
      bunsenId: 'some.path',
      value: 'value'
    })
  })
})

describe('validate action', function () {
  var SCHEMA_WITH_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName']
  }
  var SCHEMA_WITH_OBJECT_DEFAULTS = {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'Bruce'
      },
      lastName: {
        type: 'string',
        default: 'Wayne'
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      },
      onlyChild: {
        type: 'boolean',
        default: true
      },
      age: {
        type: 'number',
        title: 'Age'
      }
    },
    required: ['lastName'],
    default: {
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman'
    }
  }
  var SCHEMA_WITH_DEEP_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string',
                default: 'Bruce'
              },
              lastName: {
                type: 'string',
                default: 'Wayne'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname',
        default: 'Batman'
      }
    },
    required: ['alias']
  }

  var SCHEMA_WITH_REFS = {
    type: 'object',
    properties: {
      hero: {
        type: 'object',
        '$ref': '#/definitions/superhero'
      }
    },
    required: ['hero'],
    definitions: {
      superhero: {
        type: 'object',
        properties: {
          firstName: {
            type: 'string',
            default: 'Bruce'
          },
          lastName: {
            type: 'string',
            default: 'Wayne'
          },
          alias: {
            type: 'string',
            title: 'Nickname',
            default: 'Batman'
          }
        }
      }
    }
  }

  var SCHEMA_WITH_NO_DEFAULTS = {
    type: 'object',
    properties: {
      someotherProp: {
        type: 'object',
        properties: {
          name: {
            type: 'object',
            properties: {
              firstName: {
                type: 'string'
              },
              lastName: {
                type: 'string'
              }
            }
          }
        }
      },
      alias: {
        type: 'string',
        title: 'Nickname'
      }
    }
  }

  var SCHEMA_WITH_ARRAY_DEFAULTS = {
    type: 'object',
    properties: {
      superheroes: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            firstName: {
              type: 'string',
              default: 'Bruce'
            },
            lastName: {
              type: 'string',
              default: 'Wayne'
            },
            alias: {
              type: 'string',
              title: 'Nickname',
              default: 'Batman'
            }
          }
        }
      }
    }
  }

  function getDefaultValue (path, initialValue, schema) {
    var thunk = actions.validate(path, initialValue, schema, [])
    var defaultValue = {}

    thunk(function (action) {
      _.assign(defaultValue, action.value)
    }, function () { return {} })

    return defaultValue
  }
  it('fills in defaults', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne',
      alias: 'Batman',
      onlyChild: true
    })
  })

  it('fills in defaults for specific values', function () {
    var defaultValue = getDefaultValue('someotherProp.name', {}, SCHEMA_WITH_DEEP_DEFAULTS)

    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne'
    })
  })

  it('handles defaults in deep objects', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_DEEP_DEFAULTS)
    expect(defaultValue).to.eql({
      someotherProp: {
        name: {
          firstName: 'Bruce',
          lastName: 'Wayne'
        }
      },
      alias: 'Batman'
    })
  })

  it('handles defaults for objects', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_OBJECT_DEFAULTS)
    expect(defaultValue).to.eql({
      firstName: 'Clark',
      lastName: 'Kent',
      alias: 'Superman',
      onlyChild: true
    })
  })

  it('handles defaults in refs', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_REFS)
    expect(defaultValue).to.eql({
      hero: {
        firstName: 'Bruce',
        lastName: 'Wayne',
        alias: 'Batman'
      }
    })
  })

  it('handles a schema with no defaults', function () {
    var defaultValue = getDefaultValue(null, {}, SCHEMA_WITH_NO_DEFAULTS)
    expect(defaultValue).to.eql({})
  })

  function getState () {
    return {
      get value () {
        return {}
      }
    }
  }

  it('resolves if no validators are given', function () {
    var schema = _.cloneDeep(SCHEMA_WITH_DEFAULTS)
    delete schema.required
    var thunk = actions.validate(null, {}, schema, [])
    thunk(function (action) {
      if (action.type === actions.VALIDATION_RESOLVED) {
        expect(action.errors).to.eql({})
      }
    }, getState)
  })

  describe('when value is the same', function () {
    var schema, state, spy

    beforeEach(function () {
      schema = _.cloneDeep(SCHEMA_WITH_NO_DEFAULTS)
      spy = sinon.spy()
      state = {
        value: {
          alias: 'Bob'
        }
      }
    })

    // NOTE: the full form value always re-triggers validation. Otherwise we get
    // ourselves into a state where defaults aren't applied.
    describe('check entire form for changes', function () {
      it('dispatches action', function () {
        var thunk = actions.validate(null, _.cloneDeep(state.value), schema, [])

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount).to.equal(1)
      })

      it('dispatches action when forceValidation is disabled', function () {
        var thunk = actions.validate(null, _.cloneDeep(state.value), schema, [], Promise.all, false)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount).to.equal(1)
      })

      it('dispatches action when forceValidation is enabled', function () {
        var thunk = actions.validate(null, _.cloneDeep(state.value), schema, [], Promise.all, true)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount).to.equal(1)
      })
    })

    describe('check property for changes', function () {
      it('does not dispatch action', function () {
        var thunk = actions.validate('alias', _.cloneDeep(state.value.alias), schema, [])

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount).to.equal(0)
      })

      it('does not dispatch action when forceValidation is disabled', function () {
        var thunk = actions.validate('alias', _.cloneDeep(state.value.alias), schema, [], Promise.all, false)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount).to.equal(0)
      })

      it('dispatches action when forceValidation is enabled', function () {
        var thunk = actions.validate('alias', _.cloneDeep(state.value.alias), schema, [], Promise.all, true)

        thunk(
          spy,
          function () {
            return _.cloneDeep(state)
          }
        )

        expect(spy.callCount).to.equal(1)
      })
    })
  })

  it('handles defaults for new array elements', function () {
    var defaultValue = getDefaultValue('superheroes.0', {}, SCHEMA_WITH_ARRAY_DEFAULTS)

    expect(defaultValue).to.eql({
      firstName: 'Bruce',
      lastName: 'Wayne',
      alias: 'Batman'
    })
  })
})
<|endoftext|>


<commit_before>NEWSBLUR.AssetModel = function() {
    var _Reader = null;

    return {
        reader: function(){
            if(!_Reader){
                _Reader = new NEWSBLUR.AssetModel.Reader();
                _Reader.init();
            } else {
                _Reader.init();
            }
            return _Reader;
        },
        preferences: function(){
            if(!_Prefs){
                _Prefs = new NEWSBLUR.AssetModel.Preferences();
                _Prefs.init();
            } else {
                _Prefs.init();
            }
            return _Prefs;
        }
    };
}();

NEWSBLUR.AssetModel.Reader = function() {
    this.feeds = {};
    this.stories = {};
};

NEWSBLUR.AssetModel.Reader.prototype = {

    init: function() {
        return;
    },

    make_request: function(url, data, callback, error_callback) {
        $.ajax({
            url: url,
            data: data,
            type: 'POST',
            dataType: 'json',
            complete: function(a) {
                // NEWSBLUR.log(['make_request complete', a]);
            },
            success: function(o) {
                // NEWSBLUR.log(['make_request 1', o]);
                // var log_index = o.indexOf('<div id="django_debug"');
                var data;

                // if (log_index != -1) { // Debug is True
                //     var log = o.substring(log_index);
                //     var raw_data = o.substring(0, log_index);
                //     data = eval('(' + raw_data + ')');
                //     if (log) {
                //         $('#django_debug').remove();
                //         $('body').append(log);
                //     }
                // } else {
                    try {
                        // NEWSBLUR.log(['make_request 2', o, data]);
                        data = eval('(' + o + ')');
                    } catch(e) {
                        data = o;
                    }
                // }

                if (callback && typeof callback == 'function'){
                    callback(data);
                }
            },
            error: function(e) {
                NEWSBLUR.log(['AJAX Error', e]);
                error_callback();
            }
        });
    },

    mark_story_as_read: function(story_id, feed_id, callback) {
        var self = this;
        var read = false;

        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                read = this.stories[s].read_status;
                this.stories[s].read_status = 1;
                break;
            }
        }

        if (!read && NEWSBLUR.Globals.is_authenticated) {
            this.make_request('/reader/mark_story_as_read',
                {
                    story_id: story_id,
                    feed_id: feed_id
                }, callback
            );
        } else {
            callback(read);
        }
    },

    mark_story_as_like: function(story_id, callback) {
        var self = this;
        var opinion;

        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                opinion = this.stories[s].opinion;
                this.stories[s].opinion = 1;
                break;
            }
        }

        NEWSBLUR.log(['Like', opinion, this.stories[s].opinion]);
        if (opinion != 1) {
            this.make_request('/reader/mark_story_as_like',
                {
                    story_id: story_id
                }, callback
            );
        }
    },

    mark_story_as_dislike: function(story_id, callback) {
        var self = this;
        var opinion;

        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                opinion = this.stories[s].opinion;
                this.stories[s].opinion = -1;
                break;
            }
        }
        NEWSBLUR.log(['Dislike', opinion, this.stories[s].opinion]);
        if (opinion != -1) {
            this.make_request('/reader/mark_story_as_dislike',
                {
                    story_id: story_id
                }, callback
            );
        }
    },

    mark_feed_as_read: function(feed_id, callback) {
        var self = this;

        this.make_request('/reader/mark_feed_as_read',
            {
                feed_id: feed_id
            }, callback
        );
    },

    load_feeds: function(callback) {
        var self = this;

        var pre_callback = function(folders) {
            self.folders = folders;
            callback(folders);
        };

        this.make_request('/reader/load_feeds', {}, pre_callback);
    },

    load_feed: function(feed_id, page, first_load, callback, error_callback) {
        var self = this;

        var pre_callback = function(data) {
            // NEWSBLUR.log(['pre_callback', data]);
            if (feed_id != self.feed_id) {
                self.stories = data.stories;
                self.feed_tags = data.feed_tags;
                self.feed_authors = data.feed_authors;
                self.feed_id = feed_id;
            } else {
                $.merge(self.stories, data.stories);
            }
            callback(data, first_load);
        };

        // NEWSBLUR.log(['load_feed', feed_id, page, first_load, callback, pre_callback]);
        this.make_request('/reader/load_single_feed',
            {
                feed_id: feed_id,
                page: page
            }, pre_callback,
            error_callback
        );
    },

    load_feed_page: function(feed_id, page, callback) {
        var self = this;

        this.make_request('/reader/load_feed_page',
            {
                feed_id: feed_id,
                page: page
            }, callback
        );
    },

    get_feed: function(feed_id, callback) {
        var self = this;
        for (fld in this.folders) {
            var feeds = this.folders[fld].feeds;
            for (f in feeds) {
                if (feeds[f].id == feed_id) {
                    return feeds[f];
                }
            }
        }
        return null;
    },

    get_feed_tags: function() {
        return this.feed_tags;
    },

    get_feed_authors: function() {
        return this.feed_authors;
    },

    get_story: function(story_id, callback) {
        var self = this;
        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                return this.stories[s];
            }
        }
        return null;
    },

    process_opml_import: function(data, callback) {
        var self = this;

        this.make_request('/opml_import/process', data, callback);
    },

    save_classifier_story: function(story_id, data, callback) {
        this.make_request('/classifier/save/story/', data, callback);
    },

    save_classifier_publisher: function(data, callback) {
        this.make_request('/classifier/save/publisher', data, callback);
    }

};

NEWSBLUR.AssetModel.Preferences = function() {
    this.feeds = {};
    this.stories = {};
};

NEWSBLUR.AssetModel.Preferences.prototype = {

    init: function() {
        return;
    },

    make_request: function(url, data, callback) {
        $.ajax({
            url: url,
            data: data,
            type: 'POST',
            success: function(o) {
                var data = eval('(' + o + ')');
                if(callback && typeof callback == 'function'){
                    callback(data);
                }
            }
        });
    }

};

<commit_msg>Fixing unread counts dynamically reducing on reads.<commit_after>NEWSBLUR.AssetModel = function() {
    var _Reader = null;

    return {
        reader: function(){
            if(!_Reader){
                _Reader = new NEWSBLUR.AssetModel.Reader();
                _Reader.init();
            } else {
                _Reader.init();
            }
            return _Reader;
        },
        preferences: function(){
            if(!_Prefs){
                _Prefs = new NEWSBLUR.AssetModel.Preferences();
                _Prefs.init();
            } else {
                _Prefs.init();
            }
            return _Prefs;
        }
    };
}();

NEWSBLUR.AssetModel.Reader = function() {
    this.feeds = {};
    this.stories = {};
};

NEWSBLUR.AssetModel.Reader.prototype = {

    init: function() {
        return;
    },

    make_request: function(url, data, callback, error_callback) {
        $.ajax({
            url: url,
            data: data,
            type: 'POST',
            dataType: 'json',
            complete: function(a) {
                // NEWSBLUR.log(['make_request complete', a]);
            },
            success: function(o) {
                // NEWSBLUR.log(['make_request 1', o]);

                if (callback && typeof callback == 'function'){
                    callback(o);
                }
            },
            error: function(e) {
                NEWSBLUR.log(['AJAX Error', e]);
                error_callback();
            }
        });
    },

    mark_story_as_read: function(story_id, feed_id, callback) {
        var self = this;
        var read = false;

        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                read = this.stories[s].read_status ? true : false;
                this.stories[s].read_status = true;
                break;
            }
        }

        if (!read && NEWSBLUR.Globals.is_authenticated) {
            this.make_request('/reader/mark_story_as_read', {
                story_id: story_id,
                feed_id: feed_id
            });
        }

        callback(read);
    },

    mark_story_as_like: function(story_id, callback) {
        var self = this;
        var opinion;

        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                opinion = this.stories[s].opinion;
                this.stories[s].opinion = 1;
                break;
            }
        }

        NEWSBLUR.log(['Like', opinion, this.stories[s].opinion]);
        if (opinion != 1) {
            this.make_request('/reader/mark_story_as_like',
                {
                    story_id: story_id
                }, callback
            );
        }
    },

    mark_story_as_dislike: function(story_id, callback) {
        var self = this;
        var opinion;

        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                opinion = this.stories[s].opinion;
                this.stories[s].opinion = -1;
                break;
            }
        }
        NEWSBLUR.log(['Dislike', opinion, this.stories[s].opinion]);
        if (opinion != -1) {
            this.make_request('/reader/mark_story_as_dislike',
                {
                    story_id: story_id
                }, callback
            );
        }
    },

    mark_feed_as_read: function(feed_id, callback) {
        var self = this;

        this.make_request('/reader/mark_feed_as_read',
            {
                feed_id: feed_id
            }, callback
        );
    },

    load_feeds: function(callback) {
        var self = this;

        var pre_callback = function(folders) {
            self.folders = folders;
            callback(folders);
        };

        this.make_request('/reader/load_feeds', {}, pre_callback);
    },

    load_feed: function(feed_id, page, first_load, callback, error_callback) {
        var self = this;

        var pre_callback = function(data) {
            // NEWSBLUR.log(['pre_callback', data]);
            if (feed_id != self.feed_id) {
                self.stories = data.stories;
                self.feed_tags = data.feed_tags;
                self.feed_authors = data.feed_authors;
                self.feed_id = feed_id;
            } else {
                $.merge(self.stories, data.stories);
            }
            callback(data, first_load);
        };

        // NEWSBLUR.log(['load_feed', feed_id, page, first_load, callback, pre_callback]);
        this.make_request('/reader/load_single_feed',
            {
                feed_id: feed_id,
                page: page
            }, pre_callback,
            error_callback
        );
    },

    load_feed_page: function(feed_id, page, callback) {
        var self = this;

        this.make_request('/reader/load_feed_page',
            {
                feed_id: feed_id,
                page: page
            }, callback
        );
    },

    get_feed: function(feed_id, callback) {
        var self = this;
        for (fld in this.folders) {
            var feeds = this.folders[fld].feeds;
            for (f in feeds) {
                if (feeds[f].id == feed_id) {
                    return feeds[f];
                }
            }
        }
        return null;
    },

    get_feed_tags: function() {
        return this.feed_tags;
    },

    get_feed_authors: function() {
        return this.feed_authors;
    },

    get_story: function(story_id, callback) {
        var self = this;
        for (s in this.stories) {
            if (this.stories[s].id == story_id) {
                return this.stories[s];
            }
        }
        return null;
    },

    process_opml_import: function(data, callback) {
        var self = this;

        this.make_request('/opml_import/process', data, callback);
    },

    save_classifier_story: function(story_id, data, callback) {
        this.make_request('/classifier/save/story/', data, callback);
    },

    save_classifier_publisher: function(data, callback) {
        this.make_request('/classifier/save/publisher', data, callback);
    }

};

NEWSBLUR.AssetModel.Preferences = function() {
    this.feeds = {};
    this.stories = {};
};

NEWSBLUR.AssetModel.Preferences.prototype = {

    init: function() {
        return;
    },

    make_request: function(url, data, callback) {
        $.ajax({
            url: url,
            data: data,
            type: 'POST',
            success: function(o) {
                var data = eval('(' + o + ')');
                if(callback && typeof callback == 'function'){
                    callback(data);
                }
            }
        });
    }

};

<|endoftext|>


<commit_before>var router = require('express').Router();
var bufferClient = require('../lib/bufferClient');
var async = require('async');
var Tweet = require('../models/Tweet');
var bugsnag = require('bugsnag');
var User = require('../models/User');

router.post('/add', function (req, res) {
  var request_token = decodeURIComponent(req.query.request_token);
  var twitter_username = decodeURIComponent(req.query.twitter_username);
  var ownerEmail = decodeURIComponent(req.query.email);
  var tweets = req.body;

  if (!request_token) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'request_token missing'
    });
    return;
  }

  if (!twitter_username) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'twitter_username missing'
    });
    return;
  }

  if (!tweets) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'tweets missing'
    });
    return;
  }

  if (tweets.length === 0) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'empty tweets'
    });
    return;
  }

  async
    .waterfall([
      function (callback) {
        bufferClient.getAccessToken(request_token, callback);
      },
      function (accessToken, callback) {
        bufferClient.getTwitterProfile(accessToken, twitter_username, function (err, profile) {
          if (err) {
            callback(err);
            return;
          }

          callback(null, accessToken, profile.id);
        });
      },
      function (accessToken, profileId, callback) {
        addTweetsToBufferQueueAndIgnorePocketItem(accessToken, profileId, tweets, ownerEmail, callback);
      }
    ], function (err) {
      if (err) {
        res.statusCode = 500;
        res.json({
          status: 'error',
          message: err.message
        });
        return;
      }

      res.json({
        status: 'ok'
      });
    });
});

function addTweetsToBufferQueueAndIgnorePocketItem (accessToken, profileId, tweets, ownerEmail, callback) {
  async.waterfall([
    function (next) {
      getUserByEmail(ownerEmail, function (err, result) {
        if (err) {
          // swallow errors
          bugsnag.notify(err);
        }

        next(null, result);
      });
    },
    function (user, next) {
      addTweetsToBufferQueue(accessToken, profileId, tweets, user ? user._id : null, next)
    }
  ], callback);
}

function getUserByEmail (email, callback) {
  if (email == null) {
    callback();
    return;
  }

  User.findOne({
    email: email
  }, function (err, result) {
    if (err) {
      callback(err);
      return;
    }

    callback(null, result);
  });
}

function addTweetsToBufferQueue (accessToken, profileId, tweets, ownerId, done) {
  async.eachSeries(
    tweets,
    function (tweet, callback) {
      bufferClient.addItemToQueue(accessToken, profileId, tweet, function (err) {
        if (err) {
          callback(err);
          return;
        }

        // custom tweets do not have a pocket id
        if (tweet.pocketId == null) {
          callback();
          return;
        }

        if (ownerId == null) {
          callback();
          return;
        }

        new Tweet({
          content: tweet.content,
          image: tweet.image || '',
          pocket_item_id: tweet.pocketId,
          owner_id: ownerId
        }).save(function (err) {
          if (err) {
            // do not stop execution at this point
            // for a database error
            bugsnag.notify(err);
          }

          callback();
        });
      });
    },
    done
  );
}

module.exports = router;
<commit_msg>fail gracefully if provided twitter user name is not associated with buffer account<commit_after>var router = require('express').Router();
var bufferClient = require('../lib/bufferClient');
var async = require('async');
var Tweet = require('../models/Tweet');
var bugsnag = require('bugsnag');
var User = require('../models/User');

router.post('/add', function (req, res) {
  var request_token = decodeURIComponent(req.query.request_token);
  var twitter_username = decodeURIComponent(req.query.twitter_username);
  var ownerEmail = decodeURIComponent(req.query.email);
  var tweets = req.body;

  if (!request_token) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'request_token missing'
    });
    return;
  }

  if (!twitter_username) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'twitter_username missing'
    });
    return;
  }

  if (!tweets) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'tweets missing'
    });
    return;
  }

  if (tweets.length === 0) {
    res.statusCode = 400;
    res.json({
      status: 'error',
      message: 'empty tweets'
    });
    return;
  }

  async
    .waterfall([
      function (callback) {
        bufferClient.getAccessToken(request_token, callback);
      },
      function (accessToken, callback) {
        bufferClient.getTwitterProfile(accessToken, twitter_username, function (err, profile) {
          if (err) {
            callback(err);
            return;
          }

          if (profile == null) {
            callback(new Error('The twitter profile "' + twitter_username + '" is not linked to this Buffer account.'));
            return;
          }

          callback(null, accessToken, profile.id);
        });
      },
      function (accessToken, profileId, callback) {
        addTweetsToBufferQueueAndIgnorePocketItem(accessToken, profileId, tweets, ownerEmail, callback);
      }
    ], function (err) {
      if (err) {
        res.statusCode = 500;
        res.json({
          status: 'error',
          message: err.message
        });
        return;
      }

      res.json({
        status: 'ok'
      });
    });
});

function addTweetsToBufferQueueAndIgnorePocketItem (accessToken, profileId, tweets, ownerEmail, callback) {
  async.waterfall([
    function (next) {
      getUserByEmail(ownerEmail, function (err, result) {
        if (err) {
          // swallow errors
          bugsnag.notify(err);
        }

        next(null, result);
      });
    },
    function (user, next) {
      addTweetsToBufferQueue(accessToken, profileId, tweets, user ? user._id : null, next)
    }
  ], callback);
}

function getUserByEmail (email, callback) {
  if (email == null) {
    callback();
    return;
  }

  User.findOne({
    email: email
  }, function (err, result) {
    if (err) {
      callback(err);
      return;
    }

    callback(null, result);
  });
}

function addTweetsToBufferQueue (accessToken, profileId, tweets, ownerId, done) {
  async.eachSeries(
    tweets,
    function (tweet, callback) {
      bufferClient.addItemToQueue(accessToken, profileId, tweet, function (err) {
        if (err) {
          callback(err);
          return;
        }

        // custom tweets do not have a pocket id
        if (tweet.pocketId == null) {
          callback();
          return;
        }

        if (ownerId == null) {
          callback();
          return;
        }

        new Tweet({
          content: tweet.content,
          image: tweet.image || '',
          pocket_item_id: tweet.pocketId,
          owner_id: ownerId
        }).save(function (err) {
          if (err) {
            // do not stop execution at this point
            // for a database error
            bugsnag.notify(err);
          }

          callback();
        });
      });
    },
    done
  );
}

module.exports = router;
<|endoftext|>


<commit_before>const Router = require('express').Router
const multer = require('multer')
const router = new Router()
const Team = require('../src/db/Team')
const File = require('../src/db/File')
const auth = require('../src/auth')
const storage = require('../src/storage')
const { isPeriod } = require('../src/utils')

const upload = multer({ storage })
const fileupload = upload.fields([{ name: 'formfile', maxCount: 1 }, { name: 'sourcefile', maxCount: 1 }])

router.route('/')
  .get((req, res) => {
    if (!isPeriod()) return res.render('error')

    Team.findByLeaderSerial(req.user.serial)
      .then(team => {
        if (!team) {
          return res.render('submit', { user: req.user })
        }
        res.render('submit', {
          teamIdx: team.idx,
          user: req.user,
          contact: team.leader.contact,
          followers: team.followers,
          name: team.name,
          description: team.description,
          formfile: team.files.filter(v => v.type === File.TYPE.FORM_FILE).length > 0,
          sourcefile: team.files.filter(v => v.type === File.TYPE.SOURCE_FILE).length > 0
        })
      })
      .catch(err => {
        console.error(err)
        res.render('error')
      })
  })
  .post((req, res, next) => {
    res.setTimeout(1000 * 60 * 10, () => {
      console.error('request has time out')
      res.send(408)
    })
    next()
  }, fileupload, (req, res) => {
    if (!isPeriod()) return res.status(404).end()

    const body = req.body
    if (!body) {
      const error = new Error('No data recieved')
      error.code = 'ERR_NO_DATA'
      throw error
    }

    const leader = {
      name: req.user.name,
      serial: req.user.serial,
      contact: body.contact
    }
    const { name, followers, description } = body

    new Team({
      name,
      leader,
      followers: JSON.parse(followers),
      description
    }).save()
      .then(async v => {
        if (Object.keys(req.files).length < 1) return
        for (const type of Object.keys(req.files)) {
          const file = req.files[type][0]
          await File.deleteLatest(v.idx, type)
          await new File({
            type,
            hash: file.filename,
            originalName: file.originalname,
            teamIdx: v.idx
          }).save()
        }
      })
      .then(() => {
        res.json({
          success: true,
          error: null
        })
      })
      .catch(err => {
        if (err.code === 'ERR_DUP_TEAMNAME') {
          res.json({
            success: false,
            error: {
              code: err.code,
              message: '중복되는 팀명입니다.'
            }
          })
        } else {
          console.error(err)
          res.json({
            success: false,
            error: {
              code: 'ERR_INTERNAL',
              message: '무언가 잘못됐어요 ㅠㅠ'
            }
          })
        }
      })
  })

router.get('/success', (req, res) => {
  res.render('submit-success', {
    user: req.user
  })
})

router.delete('/delete/:serial', (req, res) => {
  if (!auth.hasPermission(req.user.userType, 'T') && req.user.serial !== req.params.serial) {
    return res.json({
      error: {
        code: 'ERR_NO_PERMISSION',
        message: '권한이 없습니다.'
      }
    })
  }
  Team.findByLeaderId(req.params.serial)
    .then(team =>
      team.delete()
        .then(() => File.deleteLatest(req.params.serial))
        .then(() => res.json({ success: true }))
        .catch(err => { throw err }))
    .catch(err => {
      console.error(err)
      res.json({
        error: {
          code: 'ERR_DB',
          message: '데이터베이스가 아파요.'
        }
      })
    })
})

module.exports = router
<commit_msg>Fix delete<commit_after>const Router = require('express').Router
const multer = require('multer')
const router = new Router()
const Team = require('../src/db/Team')
const File = require('../src/db/File')
const auth = require('../src/auth')
const storage = require('../src/storage')
const { isPeriod } = require('../src/utils')

const upload = multer({ storage })
const fileupload = upload.fields([{ name: 'formfile', maxCount: 1 }, { name: 'sourcefile', maxCount: 1 }])

router.route('/')
  .get((req, res) => {
    if (!isPeriod()) return res.render('error')

    Team.findByLeaderSerial(req.user.serial)
      .then(team => {
        if (!team) {
          return res.render('submit', { user: req.user })
        }
        res.render('submit', {
          teamIdx: team.idx,
          user: req.user,
          contact: team.leader.contact,
          followers: team.followers,
          name: team.name,
          description: team.description,
          formfile: team.files.filter(v => v.type === File.TYPE.FORM_FILE).length > 0,
          sourcefile: team.files.filter(v => v.type === File.TYPE.SOURCE_FILE).length > 0
        })
      })
      .catch(err => {
        console.error(err)
        res.render('error')
      })
  })
  .post((req, res, next) => {
    res.setTimeout(1000 * 60 * 10, () => {
      console.error('request has time out')
      res.send(408)
    })
    next()
  }, fileupload, (req, res) => {
    if (!isPeriod()) return res.status(404).end()

    const body = req.body
    if (!body) {
      const error = new Error('No data recieved')
      error.code = 'ERR_NO_DATA'
      throw error
    }

    const leader = {
      name: req.user.name,
      serial: req.user.serial,
      contact: body.contact
    }
    const { name, followers, description } = body

    new Team({
      name,
      leader,
      followers: JSON.parse(followers),
      description
    }).save()
      .then(async v => {
        if (Object.keys(req.files).length < 1) return
        for (const type of Object.keys(req.files)) {
          const file = req.files[type][0]
          await File.deleteLatest(v.idx, type)
          await new File({
            type,
            hash: file.filename,
            originalName: file.originalname,
            teamIdx: v.idx
          }).save()
        }
      })
      .then(() => {
        res.json({
          success: true,
          error: null
        })
      })
      .catch(err => {
        if (err.code === 'ERR_DUP_TEAMNAME') {
          res.json({
            success: false,
            error: {
              code: err.code,
              message: '중복되는 팀명입니다.'
            }
          })
        } else {
          console.error(err)
          res.json({
            success: false,
            error: {
              code: 'ERR_INTERNAL',
              message: '무언가 잘못됐어요 ㅠㅠ'
            }
          })
        }
      })
  })

router.get('/success', (req, res) => {
  res.render('submit-success', {
    user: req.user
  })
})

router.delete('/delete/:serial', (req, res) => {
  if (!auth.hasPermission(req.user.userType, 'T') && req.user.serial !== req.params.serial) {
    return res.json({
      error: {
        code: 'ERR_NO_PERMISSION',
        message: '권한이 없습니다.'
      }
    })
  }
  Team.findByLeaderSerial(req.params.serial)
    .then(team =>
      team.delete()
        .then(() => File.deleteLatest(req.params.serial))
        .then(() => res.json({ success: true }))
        .catch(err => { throw err }))
    .catch(err => {
      console.error(err)
      res.json({
        error: {
          code: 'ERR_DB',
          message: '데이터베이스가 아파요.'
        }
      })
    })
})

module.exports = router
<|endoftext|>


<commit_before>/**
 * Created by klsayhtg on 2017. 5. 16..
 */

const savedLang = Cookies.get('lang');
let currentLanguage = savedLang ? savedLang : 'zh_rCN';

if (currentLanguage === null || currentLanguage === undefined || currentLanguage === 'undefined') {
  currentLanguage = 'zh_rCN';
}

function moveToHashTab(hash) {
  if (hash !== '' && hash != null) {
    $($(`[href='${hash}']`)[0]).tab('show');
  }
}

const firstHash = window.location.hash;
moveToHashTab(firstHash);

$(window).on('hashchange', () => {
  moveToHashTab(window.location.hash);
});

const applyBottomTemplate = nunjucks.render('apply-bottom.html', {});
$('#main, #customer, #manager, #driver').append(applyBottomTemplate);

const bottomTemplate = nunjucks.render('bottom.html', {});
$('#main, #customer, #manager, #driver, #register').append(bottomTemplate);

/**
 * setLanguage
 * use $.lang[currentLanguage][languageNumber]
 */
function setLanguage(lang) {
  _.forEach($('[data-langstr]'), (elem) => {
    const $elem = $(elem);
    $elem.html($.lang[lang][$elem.data('langstr')]);
  });
  _.forEach($('input[type=submit][data-langstr]'), (elem) => {
    const $elem = $(elem);
    $elem.val($.lang[lang][$elem.data('langstr')]);
  });

  _.forEach($('[data-langimg]'), (elem) => {
    const $elem = $(elem);
    $(document).ready(() => {
      $elem.css('background-image', `url(${$.lang[lang][$elem.data('langimg')]})`);
    });
  });
  _.forEach($('[data-langsvg]'), (elem) => {
    const $elem = $(elem);
    $(document).ready(() => {
      document.getElementById($elem.data('langsvg')).src = $.lang[lang][$elem.data('langsvg')];
    });
  });

  setBottomIcons(lang);
}

function setBottomIcons(lang) {
  // hide wechat always temporally
  $('.nav-bottom-wechat').detach();

  if (['zh_rCN', 'zh_rTW'].indexOf(lang) >= 0) {
    $('.nav-bottom-facebook, .nav-bottom-instagram').hide();
  } else {
    $('.nav-bottom-facebook, .nav-bottom-instagram').show();
  }
}

// 언어 변경
$('.lang-selector').click((evt) => {
  const langtype = $(evt.target).data('langtype');
  const lang = $.langtype[currentLanguage][langtype];

  if (['zh_rCN', 'zh_rTW', 'en', 'ko'].indexOf(lang) >= 0) {
    currentLanguage = lang;
    Cookies.set('lang', lang);
    setLanguage(lang);
  }
});

// Wechat popover
$('[data-toggle=\'popover\']').popover();

// 탭 이동
$('[data-toggle=\'tab\']').click((evt) => {
  evt.preventDefault();
  const $target = $(evt.currentTarget);
  location.href = `/${$target.attr('href')}`;
  $('html, body').animate({
    scrollTop: 0,
  }, 600);
});

/*
 추가적으로 유용한 처리.
 1. 브라우저 언어에 따라 최초 언어 셋팅하기
 2. 외부에서 URL ?lang=ja 접근시 셋팅하기
 */

const questions = {};
questions.en = [
  'Company Name',
  'Phone Number',
  'Company Address',
  'Company email address',
  'Login ID',

  'Which Language option do you want to use?',
  'Where is your company’s base city?',
  'Do you also need to manage long-term contracted / leased drivers?',
  'Which type of car do you own?',
  'Where do your rides travel?',

  'Do you want to take easiway, OTA orders?',
];
questions.zh_rCN = [
  '公司名称', '联系方式', '公司详细地址', '公司邮箱地址', '登录账号',

  '语言设置', '贵公司业务所覆盖的城市', '是否需要管理长租/固定合同的司机？', '贵公司的车辆类型有哪些？', '公司提供服务的区域类型？',

  '贵公司可以接受易路的订单吗？',
];
questions.zh_rTW = [];

const descriptions = {};
descriptions.en = [
  'Enter your company’s full name', null, null, null, null,

  null, null, null, 'Select all that applies to your company', 'Select all that applies to your company',

  null,
];
descriptions.zh_rCN = [
  '输入贵公司的全称', null, null, null, null,

  null, null, null, '请选择贵公司拥有的所有车辆类型', '请选择贵公司拥有的所有车辆类型',

  null,
];
descriptions.zh_rTW = [];

const questionsTypeArr = [
  'text', 'text', 'text', 'email', 'text',

  'radio', 'radio', 'radio', 'checkbox', 'checkbox',

  'radio',
];

const yesOrNo = [
  {
    name: 'yesOrNo',
    value: 'true',
    label: {
      en: 'Yes',
      zh_rCN: '是',
      zh_rTW: '',
    },
  },
  {
    name: 'yesOrNo',
    value: 'false',
    label: {
      en: 'No',
      zh_rCN: '否',
      zh_rTW: '',
    },
  },
];
const cities = [];
const cityValues = [
  0, 1, 2, 3, 5,
  6, 1000, 2000, 2001, -1,
];
const cityNames = {};
cityNames.en = [
  'Shenzhen', 'Hongkong', 'Macau', 'Zhuhai', 'Meizhou',
  'Guangzhou', 'Taiwan', 'Jakarta', 'Bali', 'Etc',
];
cityNames.zh_rCN = [
  '深圳', '香港', '澳门', '珠海', '梅州',
  '广州', '台灣', 'Jakarta', 'Bali', 'Etc',
];
cityNames.zh_rTW = [];

for (let i = 0; i < cityNames.en.length; i++) {
  cities.push({
    name: 'city',
    value: cityValues[i],
    label: {
      en: cityNames.en[i],
      zh_rCN: cityNames.zh_rCN[i] || '',
      zh_rTW: cityNames.zh_rTW[i] || '',
    },
  });
}

const langs = [];
const langValues = [
  'zh_rCN', 'zh_rTW', 'en',
];
const langNames = {};
langNames.en = [
  '中文简体', '中文繁体', 'English',
];
langNames.zh_rCN = [
  '中文简体', '中文繁体', 'English',
];
langNames.zh_rTW = [];

for (let i = 0; i < langNames.en.length; i++) {
  langs.push({
    name: 'lang',
    value: langValues[i],
    label: {
      en: langNames.en[i],
      zh_rCN: langNames.zh_rCN[i] || '',
      zh_rTW: langNames.zh_rTW[i] || '',
    },
  });
}

const vans = [];
const vanValues = [
  0, 1, 2, 3, 4,
  5, 6,
];
const vanNames = {};
vanNames.en = [
  'Van (Alphard or Similar)',
  'Sedan (Camry or similar)',
  'Cross-border Van',
  'Cross-border Sedan',
  'Bus (49-person)',

  'Mini Bus (21-person)',
  'Black Sedan (A6 similar)',
];
vanNames.zh_rCN = [
  '商务车（丰田埃尔法或类似车型）',
  '轿车（凯美瑞或类似车型）',
  '跨境商务车',
  '跨境轿车',
  '大巴（49座）',

  '中巴（21座）',
  '豪华轿车（奥迪A6或类似车型）',
];
vanNames.zh_rTW = [];

for (let i = 0; i < vanNames.en.length; i++) {
  vans.push({
    name: 'van',
    value: vanValues[i],
    label: {
      en: vanNames.en[i],
      zh_rCN: vanNames.zh_rCN[i] || '',
      zh_rTW: vanNames.zh_rTW[i] || '',
    },
  });
}

const options = [
  null, null, null, null, null,

  langs, cities, yesOrNo, vans, cities,

  yesOrNo,
];

const names = [
  'name',
  'phone',
  'address',
  'email',
  'login',

  'locale',
  'base_city',
  'log_driving_record',
  'car_types',
  'service_region',

  'easiway_ind',
];

function prepareTranslations() {
  const questionsLength = questions.en.length;
  _.forEach(['en', 'zh_rCN', 'zh_rTW'], (lang) => {
    for (let i = 0; i < questionsLength; i++) {
      const number = i + 1;
      $.lang[lang][`register_question_${number}`] = `${number}. ${questions[lang][i]}`;
      $.lang[lang][`register_desc_${number}`] = descriptions[lang][i];
    }

    _.forEach([langs, cities, yesOrNo, vans], (optionSet) => {
      for (let i = 0; i < optionSet.length; i++) {
        const option = optionSet[i];
        $.lang[lang][`register_option_${option.name}_${option.value}`] = option.label[lang];
      }
    });
  });
}
prepareTranslations();

function renderQuestions() {
  for (let i = 0; i < 11; i++) {

    const question = {
      number: i + 1,
      name: names[i],
      required: true,
      type: questionsTypeArr[i],
      options: options[i],
      currentLanguage: currentLanguage,
    };
    const template = nunjucks.render('question.html', question);
    $('#register-form-content').append(template);
  }

  setLanguage(currentLanguage);
}

renderQuestions();

const $registerForm = $('#register-form');

function showErrorMessage(name) {
  const matcher = `#${name}-qa-box .register-a-err`;
  let errorMsg;
  if (name === 'login') {
    errorMsg = $.lang[currentLanguage].err_login_id_registered || 'This login ID is already taken.';
  } else {
    errorMsg = $.lang[currentLanguage].err_required || 'Please select one of these options.';
  }
  $(matcher).html(errorMsg);
}

function removeAllErrorMessages() {
  $('.register-a-err').html('');
}

const isLocalhost = Boolean(window.location.hostname === 'localhost' ||
  // [::1] is the IPv6 localhost address.
  window.location.hostname === '[::1]' ||
  // 127.0.0.1/8 is considered localhost for IPv4.
  window.location.hostname.match(
    /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
  )
);

function scrollToHashLocation(hash) {
  // location.href = hash;

  $(document.body).animate({
    scrollTop: $(hash).offset().top - 100,
  }, 300);
}

$registerForm.submit(() => {
  removeAllErrorMessages();
  const url = isLocalhost ? 'http://easixing.dev:9000/companies/signup_request' : $registerForm.attr('action');
  const data = $registerForm.serialize();

  const dataArr = $registerForm.serializeArray();
  const checkedServiceRegion = _.find(dataArr, {name: 'service_region'});
  const checkedCarTypes = _.find(dataArr, {name: 'car_types'});

  if (checkedCarTypes == null) {
    showErrorMessage('car_types');
    scrollToHashLocation('#car_types-qa-box');
    return false;
  }

  if (checkedServiceRegion == null) {
    showErrorMessage('service_region');
    scrollToHashLocation('#service_region-qa-box');
    return false;
  }

  const success = (res) => {
    if (res.available != null && !res.available) {
      showErrorMessage('login');
      scrollToHashLocation('#login-qa-box');
      return;
    }

    alert($.lang[currentLanguage].register_succeed || 'Thank you! We will be in touch shortly.');
    // location.href = '/';
  };
  const dataType = 'json';
  $.ajax({
    type: 'POST',
    url: url,
    data: data,
    success: success,
    dataType: dataType,
  });
  return false;
});

setLanguage(currentLanguage);
<commit_msg>주석 해제<commit_after>/**
 * Created by klsayhtg on 2017. 5. 16..
 */

const savedLang = Cookies.get('lang');
let currentLanguage = savedLang ? savedLang : 'zh_rCN';

if (currentLanguage === null || currentLanguage === undefined || currentLanguage === 'undefined') {
  currentLanguage = 'zh_rCN';
}

function moveToHashTab(hash) {
  if (hash !== '' && hash != null) {
    $($(`[href='${hash}']`)[0]).tab('show');
  }
}

const firstHash = window.location.hash;
moveToHashTab(firstHash);

$(window).on('hashchange', () => {
  moveToHashTab(window.location.hash);
});

const applyBottomTemplate = nunjucks.render('apply-bottom.html', {});
$('#main, #customer, #manager, #driver').append(applyBottomTemplate);

const bottomTemplate = nunjucks.render('bottom.html', {});
$('#main, #customer, #manager, #driver, #register').append(bottomTemplate);

/**
 * setLanguage
 * use $.lang[currentLanguage][languageNumber]
 */
function setLanguage(lang) {
  _.forEach($('[data-langstr]'), (elem) => {
    const $elem = $(elem);
    $elem.html($.lang[lang][$elem.data('langstr')]);
  });
  _.forEach($('input[type=submit][data-langstr]'), (elem) => {
    const $elem = $(elem);
    $elem.val($.lang[lang][$elem.data('langstr')]);
  });

  _.forEach($('[data-langimg]'), (elem) => {
    const $elem = $(elem);
    $(document).ready(() => {
      $elem.css('background-image', `url(${$.lang[lang][$elem.data('langimg')]})`);
    });
  });
  _.forEach($('[data-langsvg]'), (elem) => {
    const $elem = $(elem);
    $(document).ready(() => {
      document.getElementById($elem.data('langsvg')).src = $.lang[lang][$elem.data('langsvg')];
    });
  });

  setBottomIcons(lang);
}

function setBottomIcons(lang) {
  // hide wechat always temporally
  $('.nav-bottom-wechat').detach();

  if (['zh_rCN', 'zh_rTW'].indexOf(lang) >= 0) {
    $('.nav-bottom-facebook, .nav-bottom-instagram').hide();
  } else {
    $('.nav-bottom-facebook, .nav-bottom-instagram').show();
  }
}

// 언어 변경
$('.lang-selector').click((evt) => {
  const langtype = $(evt.target).data('langtype');
  const lang = $.langtype[currentLanguage][langtype];

  if (['zh_rCN', 'zh_rTW', 'en', 'ko'].indexOf(lang) >= 0) {
    currentLanguage = lang;
    Cookies.set('lang', lang);
    setLanguage(lang);
  }
});

// Wechat popover
$('[data-toggle=\'popover\']').popover();

// 탭 이동
$('[data-toggle=\'tab\']').click((evt) => {
  evt.preventDefault();
  const $target = $(evt.currentTarget);
  location.href = `/${$target.attr('href')}`;
  $('html, body').animate({
    scrollTop: 0,
  }, 600);
});

/*
 추가적으로 유용한 처리.
 1. 브라우저 언어에 따라 최초 언어 셋팅하기
 2. 외부에서 URL ?lang=ja 접근시 셋팅하기
 */

const questions = {};
questions.en = [
  'Company Name',
  'Phone Number',
  'Company Address',
  'Company email address',
  'Login ID',

  'Which Language option do you want to use?',
  'Where is your company’s base city?',
  'Do you also need to manage long-term contracted / leased drivers?',
  'Which type of car do you own?',
  'Where do your rides travel?',

  'Do you want to take easiway, OTA orders?',
];
questions.zh_rCN = [
  '公司名称', '联系方式', '公司详细地址', '公司邮箱地址', '登录账号',

  '语言设置', '贵公司业务所覆盖的城市', '是否需要管理长租/固定合同的司机？', '贵公司的车辆类型有哪些？', '公司提供服务的区域类型？',

  '贵公司可以接受易路的订单吗？',
];
questions.zh_rTW = [];

const descriptions = {};
descriptions.en = [
  'Enter your company’s full name', null, null, null, null,

  null, null, null, 'Select all that applies to your company', 'Select all that applies to your company',

  null,
];
descriptions.zh_rCN = [
  '输入贵公司的全称', null, null, null, null,

  null, null, null, '请选择贵公司拥有的所有车辆类型', '请选择贵公司拥有的所有车辆类型',

  null,
];
descriptions.zh_rTW = [];

const questionsTypeArr = [
  'text', 'text', 'text', 'email', 'text',

  'radio', 'radio', 'radio', 'checkbox', 'checkbox',

  'radio',
];

const yesOrNo = [
  {
    name: 'yesOrNo',
    value: 'true',
    label: {
      en: 'Yes',
      zh_rCN: '是',
      zh_rTW: '',
    },
  },
  {
    name: 'yesOrNo',
    value: 'false',
    label: {
      en: 'No',
      zh_rCN: '否',
      zh_rTW: '',
    },
  },
];
const cities = [];
const cityValues = [
  0, 1, 2, 3, 5,
  6, 1000, 2000, 2001, -1,
];
const cityNames = {};
cityNames.en = [
  'Shenzhen', 'Hongkong', 'Macau', 'Zhuhai', 'Meizhou',
  'Guangzhou', 'Taiwan', 'Jakarta', 'Bali', 'Etc',
];
cityNames.zh_rCN = [
  '深圳', '香港', '澳门', '珠海', '梅州',
  '广州', '台灣', 'Jakarta', 'Bali', 'Etc',
];
cityNames.zh_rTW = [];

for (let i = 0; i < cityNames.en.length; i++) {
  cities.push({
    name: 'city',
    value: cityValues[i],
    label: {
      en: cityNames.en[i],
      zh_rCN: cityNames.zh_rCN[i] || '',
      zh_rTW: cityNames.zh_rTW[i] || '',
    },
  });
}

const langs = [];
const langValues = [
  'zh_rCN', 'zh_rTW', 'en',
];
const langNames = {};
langNames.en = [
  '中文简体', '中文繁体', 'English',
];
langNames.zh_rCN = [
  '中文简体', '中文繁体', 'English',
];
langNames.zh_rTW = [];

for (let i = 0; i < langNames.en.length; i++) {
  langs.push({
    name: 'lang',
    value: langValues[i],
    label: {
      en: langNames.en[i],
      zh_rCN: langNames.zh_rCN[i] || '',
      zh_rTW: langNames.zh_rTW[i] || '',
    },
  });
}

const vans = [];
const vanValues = [
  0, 1, 2, 3, 4,
  5, 6,
];
const vanNames = {};
vanNames.en = [
  'Van (Alphard or Similar)',
  'Sedan (Camry or similar)',
  'Cross-border Van',
  'Cross-border Sedan',
  'Bus (49-person)',

  'Mini Bus (21-person)',
  'Black Sedan (A6 similar)',
];
vanNames.zh_rCN = [
  '商务车（丰田埃尔法或类似车型）',
  '轿车（凯美瑞或类似车型）',
  '跨境商务车',
  '跨境轿车',
  '大巴（49座）',

  '中巴（21座）',
  '豪华轿车（奥迪A6或类似车型）',
];
vanNames.zh_rTW = [];

for (let i = 0; i < vanNames.en.length; i++) {
  vans.push({
    name: 'van',
    value: vanValues[i],
    label: {
      en: vanNames.en[i],
      zh_rCN: vanNames.zh_rCN[i] || '',
      zh_rTW: vanNames.zh_rTW[i] || '',
    },
  });
}

const options = [
  null, null, null, null, null,

  langs, cities, yesOrNo, vans, cities,

  yesOrNo,
];

const names = [
  'name',
  'phone',
  'address',
  'email',
  'login',

  'locale',
  'base_city',
  'log_driving_record',
  'car_types',
  'service_region',

  'easiway_ind',
];

function prepareTranslations() {
  const questionsLength = questions.en.length;
  _.forEach(['en', 'zh_rCN', 'zh_rTW'], (lang) => {
    for (let i = 0; i < questionsLength; i++) {
      const number = i + 1;
      $.lang[lang][`register_question_${number}`] = `${number}. ${questions[lang][i]}`;
      $.lang[lang][`register_desc_${number}`] = descriptions[lang][i];
    }

    _.forEach([langs, cities, yesOrNo, vans], (optionSet) => {
      for (let i = 0; i < optionSet.length; i++) {
        const option = optionSet[i];
        $.lang[lang][`register_option_${option.name}_${option.value}`] = option.label[lang];
      }
    });
  });
}
prepareTranslations();

function renderQuestions() {
  for (let i = 0; i < 11; i++) {

    const question = {
      number: i + 1,
      name: names[i],
      required: true,
      type: questionsTypeArr[i],
      options: options[i],
      currentLanguage: currentLanguage,
    };
    const template = nunjucks.render('question.html', question);
    $('#register-form-content').append(template);
  }

  setLanguage(currentLanguage);
}

renderQuestions();

const $registerForm = $('#register-form');

function showErrorMessage(name) {
  const matcher = `#${name}-qa-box .register-a-err`;
  let errorMsg;
  if (name === 'login') {
    errorMsg = $.lang[currentLanguage].err_login_id_registered || 'This login ID is already taken.';
  } else {
    errorMsg = $.lang[currentLanguage].err_required || 'Please select one of these options.';
  }
  $(matcher).html(errorMsg);
}

function removeAllErrorMessages() {
  $('.register-a-err').html('');
}

const isLocalhost = Boolean(window.location.hostname === 'localhost' ||
  // [::1] is the IPv6 localhost address.
  window.location.hostname === '[::1]' ||
  // 127.0.0.1/8 is considered localhost for IPv4.
  window.location.hostname.match(
    /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
  )
);

function scrollToHashLocation(hash) {
  // location.href = hash;

  $(document.body).animate({
    scrollTop: $(hash).offset().top - 100,
  }, 300);
}

$registerForm.submit(() => {
  removeAllErrorMessages();
  const url = isLocalhost ? 'http://easixing.dev:9000/companies/signup_request' : $registerForm.attr('action');
  const data = $registerForm.serialize();

  const dataArr = $registerForm.serializeArray();
  const checkedServiceRegion = _.find(dataArr, {name: 'service_region'});
  const checkedCarTypes = _.find(dataArr, {name: 'car_types'});

  if (checkedCarTypes == null) {
    showErrorMessage('car_types');
    scrollToHashLocation('#car_types-qa-box');
    return false;
  }

  if (checkedServiceRegion == null) {
    showErrorMessage('service_region');
    scrollToHashLocation('#service_region-qa-box');
    return false;
  }

  const success = (res) => {
    if (res.available != null && !res.available) {
      showErrorMessage('login');
      scrollToHashLocation('#login-qa-box');
      return;
    }

    alert($.lang[currentLanguage].register_succeed || 'Thank you! We will be in touch shortly.');
    location.href = '/';
  };
  const dataType = 'json';
  $.ajax({
    type: 'POST',
    url: url,
    data: data,
    success: success,
    dataType: dataType,
  });
  return false;
});

setLanguage(currentLanguage);
<|endoftext|>


<commit_before>// Globals.
var GM_config = GM_getConfig();
var GM_uninstallQueue = {};
var gUserscriptsView = null;

(function() {
// Override some built-in functions, with a closure reference to the original
// function, to either handle or delegate the call.
var _origShowView = showView;
showView = function(aView) {
  if ('userscripts' == aView) {
    greasemonkeyAddons.showView();
  } else {
    greasemonkeyAddons.hideView();

    // Native code will break us, so hide from it before running it.
    if ('userscripts' == gView) gView = null;

    _origShowView(aView);
  }
};

// Set up an "observer" on the config, to keep the displayed items up to date
// with their actual state.
var observer = {
  notifyEvent: function(script, event, data) {
    if (event == "install") {
      var item = greasemonkeyAddons.addScriptToList(script);
      if (gView == "userscripts") gUserscriptsView.selectedItem = item;
      return;
    }

    // find the script's node in the listbox
    var listbox = gExtensionsView;
    var node = document.getElementById('urn:greasemonkey:item:'+script.id);
    if (!node) return;

    switch (event) {
      case "edit-enabled":
        node.setAttribute('isDisabled', !data);
        break;
      case "uninstall":
        gUserscriptsView.removeChild(node);
        break;
      case "move":
        gUserscriptsView.insertBefore(node, gUserscriptsView.childNodes[data]);
        break;
      case "modified":
        var item = greasemonkeyAddons.listitemForScript(script);
        gUserscriptsView.replaceChild(item, node);
        break;
    }
  }
};

// Set event listeners.
window.addEventListener('load', function() {
  gUserscriptsView = document.getElementById('userscriptsView');
  greasemonkeyAddons.fillList();

  gUserscriptsView.addEventListener(
      'select', greasemonkeyAddons.updateLastSelected, false);
  gUserscriptsView.addEventListener(
      'keypress', greasemonkeyAddons.onKeypress, false);

  GM_config.addObserver(observer);

  // Work-around for Stylish compatibility, which does not update gView in
  // its overridden showView() function.
  var stylishRadio = document.getElementById('userstyles-view');
  if (stylishRadio) {
    stylishRadio.addEventListener(
        'command',
        function() {
          greasemonkeyAddons.hideView();
          gView = 'userstyles'
        },
        false);
  }
}, false);

window.addEventListener('unload', function() {
  GM_config.removeObserver(observer);

  for (var id in GM_uninstallQueue) {
    GM_config.uninstall(GM_uninstallQueue[id]);
    delete(GM_uninstallQueue[id]);
  }
  // Guarantee that the config.xml is saved to disk.
  // Todo: This without dipping into private members.
  GM_config._save(true);
}, false);
})();

var greasemonkeyAddons = {
  showView: function() {
    gUserscriptsView = document.getElementById('userscriptsView');
    if ('userscripts' == gView) return;

    document.getElementById('viewGroup')
        .setAttribute('last-selected', 'userscripts');
    greasemonkeyAddons.reselectLastSelected();
    gView='userscripts';
    document.documentElement.className += ' userscripts';

    GM_config.updateModifiedScripts();
    gUserscriptsView.focus();
  },

  hideView: function() {
    if ('userscripts' != gView) return;
    document.documentElement.className =
      document.documentElement.className.replace(/ *\buserscripts\b/, '');
    gExtensionsView.focus();
  },

  updateLastSelected: function() {
    if (!gUserscriptsView.selectedItem) return;
    var userscriptsRadio = document.getElementById('userscripts-view');
    var selectedId = gUserscriptsView.selectedItem.getAttribute('id');
    if (selectedId) {
      userscriptsRadio.setAttribute('last-selected', selectedId);
    }
  },

  fillList: function() {
    // Remove any pre-existing contents.
    while (gUserscriptsView.firstChild) {
      gUserscriptsView.removeChild(gUserscriptsView.firstChild);
    }

    // Add a list item for each script.
    for (var i = 0, script = null; script = GM_config.scripts[i]; i++) {
      greasemonkeyAddons.addScriptToList(script);
    }

    greasemonkeyAddons.reselectLastSelected();
  },

  reselectLastSelected: function() {
    if (!gUserscriptsView) return;

    var userscriptsRadio = document.getElementById('userscripts-view');
    var lastId = userscriptsRadio.getAttribute('last-selected');

    // I have no idea why, but this setTimeout makes it work.
    setTimeout(function() {
          if ('userscripts' == gView) {
            if (lastId) {
              gUserscriptsView.selectedItem = document.getElementById(lastId);
            }
            gUserscriptsView.scrollBoxObject
                .scrollToElement(gUserscriptsView.selectedItem);
          }
        }, 0);
  },

  listitemForScript: function(script) {
    var item = document.createElement('richlistitem');

    // Setting these attributes inherits the values into the same place they
    // would go for extensions.
    item.setAttribute('addonId', script.id);
    item.setAttribute('name', script.name);
    item.setAttribute('description', script.description);
    item.setAttribute('version', script.version);
    item.setAttribute('id', 'urn:greasemonkey:item:'+script.id);
    item.setAttribute('isDisabled', !script.enabled);
    if (script.id in GM_uninstallQueue) {
      item.setAttribute('opType', 'needs-uninstall');
    }

    return item;
  },

  addScriptToList: function(script, beforeNode) {
    var item = greasemonkeyAddons.listitemForScript(script);
    gUserscriptsView.insertBefore(item, beforeNode || null);
    return item;
  },

  findSelectedScript: function() {
    if (!gUserscriptsView.selectedItem) return null;
    var scripts = GM_config.scripts;
    var selectedScriptId = gUserscriptsView.selectedItem.getAttribute('addonId');
    for (var i = 0, script = null; script = scripts[i]; i++) {
      if (selectedScriptId == script.id) {
        return script;
      }
    }
    return null;
  },

  doCommand: function(command) {
    var script = greasemonkeyAddons.findSelectedScript();
    if (!script) {
      dump("greasemonkeyAddons.doCommand() could not find selected script.\n");
      return;
    }

    var selectedListitem = gUserscriptsView.selectedItem;
    switch (command) {
    case 'cmd_userscript_edit':
      GM_openInEditor(script);
      break;
    case 'cmd_userscript_enable':
      script.enabled = true;
      break;
    case 'cmd_userscript_disable':
      script.enabled = false;
      break;
    case 'cmd_userscript_move_down':
      GM_config.move(script, 1);
      break;
    case 'cmd_userscript_move_bottom':
      GM_config.move(script, GM_config.scripts.length);
      break;
    case 'cmd_userscript_move_up':
      GM_config.move(script, -1);
      break;
    case 'cmd_userscript_move_top':
      GM_config.move(script, -1 * GM_config.scripts.length);
      break;
    case 'cmd_userscript_sort':
      function scriptCmp(a, b) {
        return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
      }
      GM_config._scripts.sort(scriptCmp);
      GM_config._save();
      greasemonkeyAddons.fillList();
      break;
    case 'cmd_userscript_uninstall':
      GM_uninstallQueue[script.id] = script;
      // Todo: This without dipping into private members?
      script.needsUninstallEnabled = script._enabled;
      script._enabled = false;
      selectedListitem.setAttribute('opType', 'needs-uninstall');
      break;
    case 'cmd_userscript_uninstall_cancel':
      delete(GM_uninstallQueue[script.id]);
      // Todo: This without dipping into private members?
      script._enabled = script.needsUninstallEnabled;
      delete(script.needsUninstallDisabled);
      selectedListitem.removeAttribute('opType');
      break;
    case 'cmd_userscript_uninstall_now':
      delete(GM_uninstallQueue[script.id]);
      GM_config.uninstall(script);
      break;
    }
  },

  buildContextMenu: function(aEvent) {
    var script = greasemonkeyAddons.findSelectedScript();
    if (!script) {
      dump("greasemonkeyAddons.buildContextMenu() could not find selected script.\n");
      return;
    }

    function $(id) { return document.getElementById(id); }
    function setItemsHidden(hidden, idList) {
      if (idList) {
        var items = idList.map(function(id) {
          return $('userscript_context_' + id);
        });
      } else {
        var items = $('userscriptContextMenu').childNodes;
        items = Array.prototype.slice.call(items);
      }
      items.forEach(function(item) {
        item.setAttribute('hidden', hidden);
      });
    }

    var standardItems = [
      'move_up', 'move_down', 'move_top', 'move_bottom', 'sort',
      'move_separator',
      'edit', 'uninstall'];
    var uninstallItems = ['uninstall_now', 'cancelUninstall'];

    // Set everything hidden now, reveal the right selection below.
    setItemsHidden(true);

    var selectedItem = gUserscriptsView.selectedItem;
    if ('needs-uninstall' == selectedItem.getAttribute('opType')) {
      setItemsHidden(false, uninstallItems);
    } else {
      // Set visibility.
      setItemsHidden(false, standardItems);
      setItemsHidden(false, script.enabled ? ['disable'] : ['enable']);
      // Set disabled.
      var atBottom = !selectedItem.nextSibling;
      var atTop = !selectedItem.previousSibling;
      // This setTimeout moves to after whatever black magic is removing
      // these values.
      // Todo: better fix.
      setTimeout(function() {
            setElementDisabledByID('userscript_context_move_up', atTop);
            setElementDisabledByID('userscript_context_move_down', atBottom);
            setElementDisabledByID('userscript_context_move_top', atTop);
            setElementDisabledByID('userscript_context_move_bottom', atBottom);
            setElementDisabledByID('userscript_context_sort', (atTop && atBottom));
          }, 0);
    }
  },

  onKeypress: function(aEvent) {
    var viewGroup = document.getElementById("viewGroup");
    switch (aEvent.keyCode) {
      case aEvent.DOM_VK_LEFT:
      case aEvent.DOM_VK_RIGHT:
        let nextFlag = (aEvent.keyCode == aEvent.DOM_VK_RIGHT);
        if (getComputedStyle(viewGroup, "").direction == "rtl")
          nextFlag = !nextFlag;
        viewGroup.checkAdjacentElement(nextFlag);
        break;
      default:
        return; // don't consume the event
    }
    aEvent.stopPropagation();
    aEvent.preventDefault();
  }
};
<commit_msg>Bugfixes for restoring selected state.<commit_after>// Globals.
var GM_config = GM_getConfig();
var GM_uninstallQueue = {};
var gUserscriptsView = null;

(function() {
// Override some built-in functions, with a closure reference to the original
// function, to either handle or delegate the call.
var _origShowView = showView;
showView = function(aView) {
  if ('userscripts' == aView) {
    greasemonkeyAddons.showView();
  } else {
    greasemonkeyAddons.hideView();

    // Native code will break us, so hide from it before running it.
    if ('userscripts' == gView) gView = null;

    _origShowView(aView);
  }
};

// Set up an "observer" on the config, to keep the displayed items up to date
// with their actual state.
var observer = {
  notifyEvent: function(script, event, data) {
    if (event == "install") {
      var item = greasemonkeyAddons.addScriptToList(script);
      if (gView == "userscripts") gUserscriptsView.selectedItem = item;
      return;
    }

    // find the script's node in the listbox
    var listbox = gExtensionsView;
    var node = document.getElementById('urn:greasemonkey:item:'+script.id);
    if (!node) return;

    switch (event) {
      case "edit-enabled":
        node.setAttribute('isDisabled', !data);
        break;
      case "uninstall":
        gUserscriptsView.removeChild(node);
        break;
      case "move":
        gUserscriptsView.insertBefore(node, gUserscriptsView.childNodes[data]);
        break;
      case "modified":
        var item = greasemonkeyAddons.listitemForScript(script);
        gUserscriptsView.replaceChild(item, node);
        break;
    }
  }
};

// Set event listeners.
window.addEventListener('load', function() {
  gUserscriptsView = document.getElementById('userscriptsView');
  greasemonkeyAddons.fillList();

  gUserscriptsView.addEventListener(
      'select', greasemonkeyAddons.updateLastSelected, false);
  gUserscriptsView.addEventListener(
      'keypress', greasemonkeyAddons.onKeypress, false);

  GM_config.addObserver(observer);

  // Work-around for Stylish compatibility, which does not update gView in
  // its overridden showView() function.
  var stylishRadio = document.getElementById('userstyles-view');
  if (stylishRadio) {
    stylishRadio.addEventListener(
        'command',
        function() {
          greasemonkeyAddons.hideView();
          gView = 'userstyles'
        },
        false);
  }
}, false);

window.addEventListener('unload', function() {
  GM_config.removeObserver(observer);

  for (var id in GM_uninstallQueue) {
    GM_config.uninstall(GM_uninstallQueue[id]);
    delete(GM_uninstallQueue[id]);
  }
  // Guarantee that the config.xml is saved to disk.
  // Todo: This without dipping into private members.
  GM_config._save(true);
}, false);
})();

var greasemonkeyAddons = {
  showView: function() {
    gUserscriptsView = document.getElementById('userscriptsView');
    if ('userscripts' == gView) return;

    document.getElementById('viewGroup')
        .setAttribute('last-selected', 'userscripts');
    var userscriptsRadio = document.getElementById('userscripts-view');
    var viewGroup = document.getElementById("viewGroup");
    viewGroup.selectedItem = userscriptsRadio;
    greasemonkeyAddons.reselectLastSelected();
    gView='userscripts';
    document.documentElement.className += ' userscripts';

    GM_config.updateModifiedScripts();
    gUserscriptsView.focus();
  },

  hideView: function() {
    if ('userscripts' != gView) return;
    document.documentElement.className =
      document.documentElement.className.replace(/ *\buserscripts\b/, '');
    gExtensionsView.focus();
  },

  updateLastSelected: function() {
    if (!gUserscriptsView.selectedItem) return;
    var userscriptsRadio = document.getElementById('userscripts-view');
    var selectedId = gUserscriptsView.selectedItem.getAttribute('id');
    if (selectedId) {
      userscriptsRadio.setAttribute('last-selected', selectedId);
    }
  },

  fillList: function() {
    // Remove any pre-existing contents.
    while (gUserscriptsView.firstChild) {
      gUserscriptsView.removeChild(gUserscriptsView.firstChild);
    }

    // Add a list item for each script.
    for (var i = 0, script = null; script = GM_config.scripts[i]; i++) {
      greasemonkeyAddons.addScriptToList(script);
    }

    greasemonkeyAddons.reselectLastSelected();
  },

  reselectLastSelected: function() {
    if (!gUserscriptsView) return;

    var userscriptsRadio = document.getElementById('userscripts-view');
    var lastId = userscriptsRadio.getAttribute('last-selected');

    // I have no idea why, but this setTimeout makes it work.
    setTimeout(function() {
          if ('userscripts' == gView) {
            if (lastId) {
              gUserscriptsView.selectedItem = document.getElementById(lastId);
            }
            if (gUserscriptsView.selectedItem) {
              gUserscriptsView.scrollBoxObject
                  .scrollToElement(gUserscriptsView.selectedItem);
            }
          }
        }, 0);
  },

  listitemForScript: function(script) {
    var item = document.createElement('richlistitem');

    // Setting these attributes inherits the values into the same place they
    // would go for extensions.
    item.setAttribute('addonId', script.id);
    item.setAttribute('name', script.name);
    item.setAttribute('description', script.description);
    item.setAttribute('version', script.version);
    item.setAttribute('id', 'urn:greasemonkey:item:'+script.id);
    item.setAttribute('isDisabled', !script.enabled);
    if (script.id in GM_uninstallQueue) {
      item.setAttribute('opType', 'needs-uninstall');
    }

    return item;
  },

  addScriptToList: function(script, beforeNode) {
    var item = greasemonkeyAddons.listitemForScript(script);
    gUserscriptsView.insertBefore(item, beforeNode || null);
    return item;
  },

  findSelectedScript: function() {
    if (!gUserscriptsView.selectedItem) return null;
    var scripts = GM_config.scripts;
    var selectedScriptId = gUserscriptsView.selectedItem.getAttribute('addonId');
    for (var i = 0, script = null; script = scripts[i]; i++) {
      if (selectedScriptId == script.id) {
        return script;
      }
    }
    return null;
  },

  doCommand: function(command) {
    var script = greasemonkeyAddons.findSelectedScript();
    if (!script) {
      dump("greasemonkeyAddons.doCommand() could not find selected script.\n");
      return;
    }

    var selectedListitem = gUserscriptsView.selectedItem;
    switch (command) {
    case 'cmd_userscript_edit':
      GM_openInEditor(script);
      break;
    case 'cmd_userscript_enable':
      script.enabled = true;
      break;
    case 'cmd_userscript_disable':
      script.enabled = false;
      break;
    case 'cmd_userscript_move_down':
      GM_config.move(script, 1);
      break;
    case 'cmd_userscript_move_bottom':
      GM_config.move(script, GM_config.scripts.length);
      break;
    case 'cmd_userscript_move_up':
      GM_config.move(script, -1);
      break;
    case 'cmd_userscript_move_top':
      GM_config.move(script, -1 * GM_config.scripts.length);
      break;
    case 'cmd_userscript_sort':
      function scriptCmp(a, b) {
        return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
      }
      GM_config._scripts.sort(scriptCmp);
      GM_config._save();
      greasemonkeyAddons.fillList();
      break;
    case 'cmd_userscript_uninstall':
      GM_uninstallQueue[script.id] = script;
      // Todo: This without dipping into private members?
      script.needsUninstallEnabled = script._enabled;
      script._enabled = false;
      selectedListitem.setAttribute('opType', 'needs-uninstall');
      break;
    case 'cmd_userscript_uninstall_cancel':
      delete(GM_uninstallQueue[script.id]);
      // Todo: This without dipping into private members?
      script._enabled = script.needsUninstallEnabled;
      delete(script.needsUninstallDisabled);
      selectedListitem.removeAttribute('opType');
      break;
    case 'cmd_userscript_uninstall_now':
      delete(GM_uninstallQueue[script.id]);
      GM_config.uninstall(script);
      break;
    }
  },

  buildContextMenu: function(aEvent) {
    var script = greasemonkeyAddons.findSelectedScript();
    if (!script) {
      dump("greasemonkeyAddons.buildContextMenu() could not find selected script.\n");
      return;
    }

    function $(id) { return document.getElementById(id); }
    function setItemsHidden(hidden, idList) {
      if (idList) {
        var items = idList.map(function(id) {
          return $('userscript_context_' + id);
        });
      } else {
        var items = $('userscriptContextMenu').childNodes;
        items = Array.prototype.slice.call(items);
      }
      items.forEach(function(item) {
        item.setAttribute('hidden', hidden);
      });
    }

    var standardItems = [
      'move_up', 'move_down', 'move_top', 'move_bottom', 'sort',
      'move_separator',
      'edit', 'uninstall'];
    var uninstallItems = ['uninstall_now', 'cancelUninstall'];

    // Set everything hidden now, reveal the right selection below.
    setItemsHidden(true);

    var selectedItem = gUserscriptsView.selectedItem;
    if ('needs-uninstall' == selectedItem.getAttribute('opType')) {
      setItemsHidden(false, uninstallItems);
    } else {
      // Set visibility.
      setItemsHidden(false, standardItems);
      setItemsHidden(false, script.enabled ? ['disable'] : ['enable']);
      // Set disabled.
      var atBottom = !selectedItem.nextSibling;
      var atTop = !selectedItem.previousSibling;
      // This setTimeout moves to after whatever black magic is removing
      // these values.
      // Todo: better fix.
      setTimeout(function() {
            setElementDisabledByID('userscript_context_move_up', atTop);
            setElementDisabledByID('userscript_context_move_down', atBottom);
            setElementDisabledByID('userscript_context_move_top', atTop);
            setElementDisabledByID('userscript_context_move_bottom', atBottom);
            setElementDisabledByID('userscript_context_sort', (atTop && atBottom));
          }, 0);
    }
  },

  onKeypress: function(aEvent) {
    var viewGroup = document.getElementById("viewGroup");
    switch (aEvent.keyCode) {
      case aEvent.DOM_VK_LEFT:
      case aEvent.DOM_VK_RIGHT:
        let nextFlag = (aEvent.keyCode == aEvent.DOM_VK_RIGHT);
        if (getComputedStyle(viewGroup, "").direction == "rtl")
          nextFlag = !nextFlag;
        viewGroup.checkAdjacentElement(nextFlag);
        break;
      default:
        return; // don't consume the event
    }
    aEvent.stopPropagation();
    aEvent.preventDefault();
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $ */

define(function (require, exports, module) {
    'use strict';

    var Commands                = require("command/Commands"),
        CommandManager          = require("command/CommandManager"),
        SidebarView             = require("project/SidebarView"),
        ProjectManager          = require("project/ProjectManager");

    function _handleHideSidebar() {
        SidebarView.toggleSidebar();
    }

    CommandManager.register(Commands.VIEW_HIDE_SIDEBAR, _handleHideSidebar);
});
<commit_msg>Added the editor font size increase and decrease implementation.<commit_after>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $ */

define(function (require, exports, module) {
    'use strict';

    var Commands                = require("command/Commands"),
        CommandManager          = require("command/CommandManager"),
        SidebarView             = require("project/SidebarView"),
        ProjectManager          = require("project/ProjectManager"),
        EditorManager           = require("editor/EditorManager");

    function _handleHideSidebar() {
        SidebarView.toggleSidebar();
    }

    /**
     * @private
     * Increases or decreases the editor's font size.
     * @param {string} "up" or "down"
     */
    function _adjustFontSize(direction) {
        var styleId = "codemirror-dynamic-fonts";

        var fs = $(".CodeMirror-scroll").css("font-size");
        var lh = $(".CodeMirror-scroll").css("line-height");

        var fsUnits = fs.substring(fs.length - 2, fs.length);
        var lhUnits = lh.substring(lh.length - 2, lh.length);

        fs = fs.substring(0, fs.length - 2);
        lh = lh.substring(0, lh.length - 2);

        var fsDelta = (fsUnits === "px") ? 1 : 0.1;
        var lhDelta = (lhUnits === "px") ? 1 : 0.1;

        if (direction === "down") {
            fsDelta *= -1;
            lhDelta *= -1;
        }

        var fsStr = (parseFloat(fs) + fsDelta) + fsUnits;
        var lhStr = (parseFloat(lh) + lhDelta) + lhUnits;

        if (fsStr === "1px" || fsStr === ".1em") {
            return;
        }

        $("#" + styleId).remove();
        var style = window.document.createElement("style");
        style.setAttribute("type", "text/css");
        style.setAttribute("id", styleId);
        style.innerHTML = ".CodeMirror-scroll{font-size:" + fsStr +
                          " !important;line-height:" + lhStr + " !important;}";
        $("head").append(style);

        var editor = EditorManager.getFocusedEditor();
        var codeMirror = editor._codeMirror;
        codeMirror.refresh();
    }

    function _handleIncreaseFontSize() {
        _adjustFontSize("up");
    }

    function _handleDecreaseFontSize() {
        _adjustFontSize("down");
    }

    CommandManager.register(Commands.VIEW_HIDE_SIDEBAR,       _handleHideSidebar);
    CommandManager.register(Commands.VIEW_INCREASE_FONT_SIZE, _handleIncreaseFontSize);
    CommandManager.register(Commands.VIEW_DECREASE_FONT_SIZE, _handleDecreaseFontSize);
});
<|endoftext|>