diff --git a/app/locale/en.coffee b/app/locale/en.coffee index 267bb62ec..6bfecaad7 100644 --- a/app/locale/en.coffee +++ b/app/locale/en.coffee @@ -26,6 +26,14 @@ minutes: "minutes" hour: "hour" hours: "hours" + day: "day" + days: "days" + week: "week" + weeks: "weeks" + month: "month" + months: "months" + year: "year" + years: "years" modal: close: "Close" @@ -194,12 +202,99 @@ looking_for: "Looking for:" last_updated: "Last updated:" contact: "Contact" - work_experience: "Work Experience" - education: "Education" - our_notes: "Our Notes" - projects: "Projects" active: "Looking for interview offers now" inactive: "Not looking for offers right now" + complete: "complete" + next: "Next" + next_city: "city?" + next_country: "pick your country." + next_name: "name?" + next_short_description: "summarize yourself at a glance." + next_long_description: "describe the work you're looking for." + next_skills: "list at least five skills." + next_work: "list your work experience." + next_education: "recount your educational ordeals." + next_projects: "show off up to three projects you've worked on." + next_links: "add any personal or social links." + next_photo: "add an optional professional photo." + next_active: "mark yourself open to offers to show up in searches." + example_blog: "Your Blog" + example_github: "Your GitHub" + links_header: "Personal Links" + links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog." + links_name: "Link Name" + links_name_help: "What are you linking to?" + links_link_blurb: "Link URL" + basics_header: "Update basic info" + basics_active: "Open to Offers" + basics_active_help: "Want interview offers right now?" + basics_job_title: "Desired Job Title" + basics_job_title_help: "What role are you looking for?" + basics_city: "City" + basics_city_help: "City you want to work in (or live in now)." + basics_country: "Country" + basics_country_help: "Country you want to work in (or live in now)." + basics_visa: "US Work Status" + basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship?" + basics_looking_for: "Looking For" + basics_looking_for_full_time: "Full-time" + basics_looking_for_part_time: "Part-time" + basics_looking_for_remote: "Remote" + basics_looking_for_contracting: "Contracting" + basics_looking_for_internship: "Internship" + basics_looking_for_help: "What kind of developer position do you want?" + name_header: "Fill in your name" + name_anonymous: "Anonymous Developer" + name_help: "Name you want employers to see, like 'Nick Winter'." + short_description_header: "Write a short description of yourself" + short_description_blurb: "Add a blurb here that will show, at a glance, whether you might be just the developer that an employer is looking for." + short_description: "Short Description" + short_description_help: "Who are you, and what are you looking for? 140 characters max." + skills_header: "Skills" + skills_help: "Tag relevant developer skills in order of proficiency." + long_description_header: "Detail your desired position" + long_description_blurb_1: "Write a little longer section here to describe the role you would like to pursue next." + long_description_blurb_2: "Talk about how awesome you are and why it would be a good idea to hire you." + long_description: "Description" + long_description_help: "Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max." + work_experience: "Work Experience" + work_header: "Chronicle your work history" + work_years: "Years of Experience" + work_years_help: "How many years of professional experience (getting paid) developing software do you have?" + work_blurb: "List your relevant work experience, most recent first." + work_employer: "Employer" + work_employer_help: "Name of your employer." + work_role: "Job Title" + work_role_help: "What was your job title or role?" + work_duration: "Duration" + work_duration_help: "When did you hold this gig?" + work_description: "Description" + work_description_help: "What did you do there? (140 chars; optional)" + education: "Education" + education_header: "Recount your academic ordeals" + education_blurb: "List your academic ordeals." + education_school: "School" + education_school_help: "Name of your school." + education_degree: "Degree" + education_degree_help: "What was your degree and field of study?" + education_duration: "Dates" + education_duration_help: "When?" + education_description: "Description" + education_description_help: "Highlight anything about this educational experience. (140 chars; optional)" + our_notes: "Our Notes" + projects: "Projects" + projects_header: "Add 3 projects" + projects_header_2: "Projects (Top 3)" + projects_blurb: "Highlight your projects to amaze employers." + project_name: "Project Name" + project_name_help: "What was the project called?" + project_description: "Description" + project_description_help: "Briefly describe the project." + project_picture: "Picture" + project_picture_help: "Upload a 230x115px or larger image showing off the project." + project_link: "Link" + project_link_help: "Link to the project." + employers: want_to_hire_our_players: "Want to hire expert CodeCombat players?" diff --git a/app/styles/account/profile.sass b/app/styles/account/profile.sass index 50879e5c9..c4b249de2 100644 --- a/app/styles/account/profile.sass +++ b/app/styles/account/profile.sass @@ -24,10 +24,14 @@ height: 33px margin-bottom: 0 border-radius: 0 + background-color: $sideBackground .progress-bar line-height: 33px font-size: 16px + text-overflow: ellipsis + overflow: hidden + white-space: nowrap .main-content-area padding: 0 @@ -92,7 +96,7 @@ width: $side-width - 2 * $side-padding overflow-wrap: break-word - .profile-photo-container + #profile-photo-container position: relative margin-bottom: 10px @@ -241,6 +245,11 @@ .job-profile-container .editable-section position: relative + transition: box-shadow 0.5s easeInOutQuad + + &.just-saved + box-shadow: 0px 0px 80px 0px #080 + z-index: 1 .editable-form display: none @@ -294,7 +303,7 @@ code.edit-example-tag color: $blue - .editable-section.deemphasized, .our-notes-section.deemphasized + .editable-section.deemphasized:not(.just-saved), .our-notes-section.deemphasized opacity: 0.5 .editable-section:hover diff --git a/app/templates/account/profile.jade b/app/templates/account/profile.jade index 25f42d7d3..2c94d3cb9 100644 --- a/app/templates/account/profile.jade +++ b/app/templates/account/profile.jade @@ -1,8 +1,6 @@ extends /templates/base block content - - var profile = user.get('jobProfile'); - if allowedToEditJobProfile .profile-control-bar if editing @@ -36,7 +34,7 @@ block content button.btn i.icon-user span(data-i18n="account_settings.sample_profile") See a sample profile - if editing || myProfile + if editing .progress.profile-completion-progress .progress-bar.progress-bar-success(style="width: #{100 * progress}%") @@ -45,12 +43,12 @@ block content .job-profile-row .left-column.full-height-column .sub-column - .profile-photo-container.editable-section(title="Click to change your photo") + #profile-photo-container.editable-section(title="Click to change your photo") .editable-icon.glyphicon.glyphicon-pencil img.profile-photo(src=user.getPhotoURL(240, true)) .profile-caption= profile.jobTitle || 'Software Developer' - .links-container.editable-section + #links-container.editable-section .editable-display(title="Click to add social and personal links") .editable-icon.glyphicon.glyphicon-pencil if profileLinks && profileLinks.length @@ -65,26 +63,28 @@ block content button.btn.btn-large.btn-inverse.flat-button= link.name else if editing h3.edit-label(data-i18n="account_profile.add_links") Add some links - button.btn.btn-large.btn-inverse.flat-button.edit-example-button Your Blog - button.btn.btn-large.btn-inverse.flat-button.edit-example-button Your GitHub + button.btn.btn-large.btn-inverse.flat-button.edit-example-button(data-i18n="account_profile.example_blog") Your Blog + button.btn.btn-large.btn-inverse.flat-button.edit-example-button(data-i18n="account_profile.example_githu") Your GitHub form.editable-form .editable-icon.glyphicon.glyphicon-remove - h3 Personal Links - p.help-block Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog. + h3(data-i18n="account_profile.links_header") Personal Links + p.help-block(data-i18n="account_profile.links_blurb") Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog. .editable-array(data-property='links') for link, index in (profile.links || []).concat({}) .array-item.link-container.well.well-sm .form-group - label.control-label Link Name - input.form-control(type='link-name', maxlength='30', data-schemaformat='link-name', name='root[links][' + index + '][name]', value=link.name) + label.control-label(data-i18n="account_profile.links_name") Link Name + input.form-control(type='link-name', maxlength='30', data-schemaformat='link-name', name="root[links][#{index}][name]", value=link.name, data-autocomplete="commonLinkNames", data-autocomplete-min-length=0) if !index - p.help-block What are you linking to? Ex: "Personal Website", "GitHub" + p.help-block + span(data-i18n="account_profile.links_name_help") What are you linking to? + | Ex.: 'Personal Website', 'GitHub' .form-group - label.control-label Link URL - input.form-control(type='url', pattern='^(ht|f)tp(s?)://[0-9a-zA-Z]([-.w]*[0-9a-zA-Z])*(:(0-9)*)*(/?)([a-zA-Z0-9-.?,\'/\+&%$#_=]*)?$', data-schemaformat='url', name='root[links][' + index + '][link]', value=link.link) + label.control-label(data-i18n="account_profile.links_link") Link URL + input.form-control(type='url', pattern='^(ht|f)tp(s?)://[0-9a-zA-Z]([-.w]*[0-9a-zA-Z])*(:(0-9)*)*(/?)([a-zA-Z0-9-.?,\'/\+&%$#_=]*)?$', data-schemaformat='url', name="root[links][#{index}][link]", value=link.link) if !index - p.help-block Ex.: "https://github.com/nwinter" + p.help-block Ex.: "https://github.com/nwinter" button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save .editable-section.basic-info-container @@ -92,7 +92,7 @@ block content div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info") .editable-icon.glyphicon.glyphicon-pencil if editableDefaults - h3.edit-label Update basic info + h3.edit-label(data-i18n="account_profile.basics_header") Update basic info div= profile.city + ', ' + profile.country div= profile.visa div @@ -105,40 +105,44 @@ block content form.editable-form .editable-icon.glyphicon.glyphicon-remove .form-group - label.control-label Open to Offers + label.control-label(data-i18n="account_profile.basics_active") Open to Offers select.form-control(name='root[active]') - option(value='1', selected=profile.active) Yes, I want interviews - option(value='', selected=!profile.active) No, not right now - p.help-block Want interview offers right now? + option(value='1', selected=profile.active, data-i18n="account_profile.active") Looking for interview offers now + option(value='', selected=!profile.active, data-i18n="account_profile.inactive") Not looking for offers right now + p.help-block(data-i18n="account_profile.basics_active_help") Want interview offers right now? .form-group - label.control-label Desired Job Title + label.control-label(data-i18n="account_profile.basics_job_title") Desired Job Title input.form-control(type='text', maxlength='50', name='root[jobTitle]', value=profile.jobTitle) p.help-block - | What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer" + span(data-i18n="account_profile.basics_job_title_help") What role are you looking for? + | Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer" .form-group - label.control-label City - input.form-control(type='city', maxlength='100', data-schemaformat='city', name='root[city]', value=profile.city) + label.control-label(data-i18n="account_profile.basics_city") City + input.form-control(type='city', maxlength='100', data-schemaformat='city', name='root[city]', value=profile.city, data-autocomplete="commonCities", data-autocomplete-min-length=1) p.help-block - | City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX". + span(data-i18n="account_profile.basics_city_help") City you want to work in (or live in now). + | Ex.: "San Francisco", "Lubbock, TX" .form-group - label.control-label Country - input.form-control(type='country', maxlength='100', data-schemaformat='country', name='root[country]', value=profile.country) - p.help-block Country you want to work in (or live in now), like "USA" or "France". + label.control-label(data-i18n="account_profile.basics_country") Country + input.form-control(type='country', maxlength='100', data-schemaformat='country', name='root[country]', value=profile.country, data-autocomplete="commonCountries", data-autocomplete-min-length=1) + p.help-block + span(data-i18n="account_profile.basics_country_help") Country you want to work in (or live in now). + | Ex.: "USA", "France" .form-group - label.control-label US Work Status + label.control-label(data-i18n="account_profile.basics_visa") US Work Status select.form-control(name='root[visa]') option(value='Authorized to work in the US', selected=profile.visa == 'Authorized to work in the US') Authorized to work in the US option(value='Need visa sponsorship', selected=profile.visa == 'Need visa sponsorship') Need visa sponsorship - p.help-block Are you authorized to work in the US, or do you need visa sponsorship? + p.help-block(data-i18n="account_profile.basics_visa_help") Are you authorized to work in the US, or do you need visa sponsorship? .form-group - label.control-label Looking For + label.control-label(data-i18n="account_profile.basics_looking_for") Looking For select.form-control(name='root[lookingFor]') - option(value='Full-time', selected=profile.lookingFor == "Full-time") Full-time - option(value='Part-time', selected=profile.lookingFor == "Part-time") Part-time - option(value='Remote', selected=profile.lookingFor == "Remote") Remote - option(value='Contracting', selected=profile.lookingFor == "Contracting") Contracting - option(value='Internship', selected=profile.lookingFor == "Internship") Internship - p.help-block What kind of developer position do you want? + option(value='Full-time', selected=profile.lookingFor == "Full-time", data-i18n="account_profile.basics_looking_for_full_time") Full-time + option(value='Part-time', selected=profile.lookingFor == "Part-time", data-i18n="account_profile.basics_looking_for_part_time") Part-time + option(value='Remote', selected=profile.lookingFor == "Remote", data-i18n="account_profile.basics_looking_for_remote") Remote + option(value='Contracting', selected=profile.lookingFor == "Contracting", data-i18n="account_profile.basics_looking_for_contracting") Contracting + option(value='Internship', selected=profile.lookingFor == "Internship", data-i18n="account_profile.basics_looking_for_internship") Internship + p.help-block(data-i18n="account_profile.basics_looking_for_help") What kind of developer position do you want? button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save if !editing @@ -148,26 +152,31 @@ block content .middle-column.full-height-column .sub-column - .name-container.editable-section + #name-container.editable-section .editable-display(title="Click to fill in your name") .editable-icon.glyphicon.glyphicon-pencil - h3(class=editing && !profile.name ? "edit-label" : "")= profile.name || (editing ? "Fill in your name" : "Anonymous Developer") + if editing && !profile.name + h3.edit-label(data-i18n="account_profile.name_header") Fill in your name + else if profile.name + h3= profile.name + else + h3(data-i18n="account_profile.name_anonymous") Anonymous Developer form.editable-form .editable-icon.glyphicon.glyphicon-remove .form-group - label.control-label Name + label.control-label(data-i18n="general.name") Name input.form-control(type='text', maxlength='100', name='root[name]', value=profile.name) - p.help-block Name you want employers to see, like "Nick Winter". + p.help-block(data-i18n="account_profile.name_help") Name you want employers to see, like 'Nick Winter'. button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save - .short-description-container.editable-section + #short-description-container.editable-section .editable-display(title="Click to write your short description") .editable-icon.glyphicon.glyphicon-pencil if editing && (!profile.shortDescription || profile.shortDescription == jobProfileSchema.properties.shortDescription.default) - h3.edit-label(data-i18n="account_profile.add_short_description") Write a short description of yourself - p.edit-example-text Add a blurb here that will show, at a glance, whether you might be just the developer that an employer is looking for. + h3.edit-label(data-i18n="account_profile.short_description_header") Write a short description of yourself + p.edit-example-text(data-i18n="account_profile.short_description_blurb") Add a blurb here that will show, at a glance, whether you might be just the developer that an employer is looking for. else if profile.shortDescription p.editable-thinner= profile.shortDescription @@ -175,13 +184,13 @@ block content form.editable-form .editable-icon.glyphicon.glyphicon-remove .form-group - label.control-label Short Description + label.control-label(data-i18n="account_profile.short_description") Short Description textarea.form-control(rows=3, maxlength='140', name='root[shortDescription]')= profile.shortDescription - p.help-block Who are you, and what are you looking for? 140 characters max. + p.help-block(data-i18n="account_profile.short_description_help") Who are you, and what are you looking for? 140 characters max. button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save - .skills-container.editable-section + #skills-container.editable-section .editable-display.editable-thinner(title="Click to tag your programming skills") .editable-icon.glyphicon.glyphicon-pencil if editing && (!profile.skills || !profile.skills.length || (profile.skills.length == 1 && profile.skills[0] == 'javascript')) @@ -196,44 +205,44 @@ block content form.editable-form .editable-icon.glyphicon.glyphicon-remove - h3 Skills - p.help-block - | Tag relevant developer skills in order of proficiency. - | Ex.: "objective-c", "mongodb", "rails", "android", "javascript" + h3(data-i18n="account_profile.skills_header") Skills + p.help-block + span(data-i18n="account_profile.skills_help") Tag relevant developer skills in order of proficiency. + | Ex.: "objective-c", "mongodb", "rails", "android", "javascript" .editable-array(data-property='skills') for skill, index in (profile.skills || []).concat('') .array-item.skill-array-item - input.form-control(type='skill', maxlength='20', pattern='.{1,}', data-schemaformat='skill', name='root[skills][0]', value=skill) + input.form-control(type='skill', maxlength='20', pattern='.{1,}', data-schemaformat='skill', name="root[skills][#{index}]", value=skill, data-autocomplete="commonSkills", data-autocomplete-min-length=1) button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save - .long-description-container.editable-section + #long-description-container.editable-section .editable-display(title="Click to start writing your longer description") .editable-icon.glyphicon.glyphicon-pencil if editing && (!profile.longDescription || profile.longDescription == jobProfileSchema.properties.longDescription.default) - h3.edit-label Detail your desired position - p.edit-example-text Write a little longer section here to describe the role you would like to pursue next. - p.edit-example-text Talk about how awesome you are and why it would be a good idea to hire you. + h3.edit-label(data-i18n="account_profile.long_description_header") Detail your desired position + p.edit-example-text(data-i18n="account_profile.long_description_blurb_1") Write a little longer section here to describe the role you would like to pursue next. + p.edit-example-text(data-i18n="account_profile.long_description_blurb_2") Talk about how awesome you are and why it would be a good idea to hire you. else if profile.longDescription div.long-description.editable-thinner!= marked(profile.longDescription) form.editable-form .editable-icon.glyphicon.glyphicon-remove .form-group - label.control-label Description + label.control-label(data-i18n="account_profile.long_description") Description textarea.form-control(rows=20, maxlength='600', data-schemaformat='markdown', name='root[longDescription]')= profile.longDescription - p.help-block - | Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max. + p.help-block(data-i18n="account_profile.long_description_help") Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max. button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save - .work-container.editable-section + #work-container.editable-section .editable-display(title="Click to add work experience") .editable-icon.glyphicon.glyphicon-pencil if profile.work && profile.work.length h3.experience-header img.header-icon(src="/images/pages/account/profile/work.png", alt="") span(data-i18n="account_profile.work_experience") Work Experience - | - #{profile.experience} years + | - #{profile.experience} + span(data-i18n=profile.experience == 1 ? "units.year" : "units.years") each job in profile.work if job.role && job.employer div.experience-entry @@ -243,7 +252,7 @@ block content if job.description div!= marked(job.description) else if editing - h3.experience-header.edit-label Chronicle your work history + h3.experience-header.edit-label(data-i18n="account_profile.work_header") Chronicle your work history div.experience-entry.edit-example-text div.duration.pull-right June, 2012 - present @@ -259,36 +268,37 @@ block content form.editable-form .editable-icon.glyphicon.glyphicon-remove - h3 Work Experience + h3(data-i18n="account_profile.work_experience") Work Experience .form-group - label.control-label Years of Experience + label.control-label(data-i18n="account_profile.work_years") Years of Experience input.form-control(type='text', name='root[experience]') - p.help-block - | How many years of professional experience (getting paid) developing software do you have? - p List your relevant work experience, most recent first. + p.help-block(data-i18n="account_profile.work_years_help") How many years of professional experience (getting paid) developing software do you have? + p(data-i18n="account_profile.work_blurb") List your relevant work experience, most recent first. .editable-array(data-property='work') for job, index in (profile.work || []).concat({}) .array-item.well.well-sm .form-group - label.control-label Employer - input.form-control(type='text', maxlength='100', name='root[work][0][employer]', value=job.employer) - p.help-block Name of your employer. + label.control-label(data-i18n="account_profile.work_employer") Employer + input.form-control(type='text', maxlength='100', name="root[work][#{index}][employer]", value=job.employer) + p.help-block(data-i18n="account_profile.work_employer_help") Name of your employer. .form-group - label.control-label Job Title - input.form-control(type='text', maxlength='100', name='root[work][0][role]', value=job.role) - p.help-block What was your job title or role? + label.control-label(data-i18n="account_profile.work_role") Job Title + input.form-control(type='text', maxlength='100', name="root[work][#{index}][role]", value=job.role) + p.help-block(data-i18n="account_profile.work_role_help") What was your job title or role? .form-group - label.control-label Duration - input.form-control(type='text', maxlength='100', name='root[work][0][duration]', value=job.duration) - p.help-block When did you hold this gig? Ex.: "Feb 2013 - present". + label.control-label(data-i18n="account_profile.work_duration") Duration + input.form-control(type='text', maxlength='100', name="root[work][#{index}][duration]", value=job.duration) + p.help-block + span(data-i18n="account_profile.work_duration_help") When did you hold this gig? + | Ex.: "Feb 2013 - present". .form-group - label.control-label Description - textarea.form-control(rows=3, maxlength='140', name='root[work][0][description]')= job.description - p.help-block What did you do there? (140 chars; optional) + label.control-label(data-i18n="account_profile.work_description") Description + textarea.form-control(rows=3, maxlength='140', name="root[work][#{index}][description]")= job.description + p.help-block(data-i18n="account_profile.work_description_help") What did you do there? (140 chars; optional) button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save - .education-container.editable-section + #education-container.editable-section .editable-display(title="Click to add academic experience") .editable-icon.glyphicon.glyphicon-pencil if profile.education && profile.education.length @@ -304,7 +314,7 @@ block content if school.description div!= marked(school.description) else if editing - h3.experience-header.edit-label Recount your academic ordeals + h3.experience-header.edit-label(data-i18n="account_profile.education_header") Recount your academic ordeals div.experience-entry.edit-example-text div.duration.pull-right 1995 - 1997 @@ -314,28 +324,31 @@ block content form.editable-form .editable-icon.glyphicon.glyphicon-remove - h3 Education - p List your academic ordeals. + h3(data-i18n="accont_profile.education") Education + p(data-i18n="account_profile.education_blurb") List your academic ordeals. .editable-array(data-property='education') for school, index in (profile.education || []).concat({}) .array-item.well.well-sm .form-group - label.control-label School - input.form-control(type='text', maxlength='100', name='root[education][0][school]', value=school.school) - p.help-block Name of your school. + label.control-label(data-i18n="account_profile.education_school") School + input.form-control(type='text', maxlength='100', name="root[education][#{index}][school]", value=school.school) + p.help-block(data-i18n="account_profile.education_school_help") Name of your school. .form-group - label.control-label Degree - input.form-control(type='text', maxlength='100', name='root[education][0][degree]', value=school.degree) + label.control-label(data-i18n="account_profile.education_degree") Degree + input.form-control(type='text', maxlength='100', name="root[education][#{index}][degree]", value=school.degree) p.help-block - | What was your degree and field of study? Ex. Ph.D. Human-Computer Interaction (incomplete) + span(data-i18n="account_profile.education_degree_help") What was your degree and field of study? + | Ex.: "Ph.D. Human-Computer Interaction (incomplete)" .form-group - label.control-label Dates - input.form-control(type='text', maxlength='100', name='root[education][0][duration]', value=school.duration) - p.help-block When? Ex.: "Aug 2004 - May 2008". + label.control-label(data-i18n="account_profile.education_duration") Dates + input.form-control(type='text', maxlength='100', name="root[education][#{index}][duration]", value=school.duration) + p.help-block + span(data-i18n="account_profile.education_duration_help") When? + | Ex.: "Aug 2004 - May 2008". .form-group - label.control-label Description - textarea.form-control(rows=3, maxlength='140', name='root[education][0][description]')= school.description - p.help-block Highlight anything about this educational experience. (140 chars; optional) + label.control-label(data-i18n="account_profile.education_description") Description + textarea.form-control(rows=3, maxlength='140', name="root[education][#{index}][description]")= school.description + p.help-block(data-i18n="account_profile.education_description_help") Highlight anything about this educational experience. (140 chars; optional) button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save @@ -345,13 +358,13 @@ block content - var notes = user.get('jobProfileNotes') || ''; if me.isAdmin() textarea#job-profile-notes!= notes - button.btn.btn-primary#save-notes-button Save Notes + button.btn.btn-primary#save-notes-button(data-i18n="common.save") Save else div!= marked(notes) .right-column.full-height-column .sub-column - .projects-container.editable-section + #projects-container.editable-section .editable-display(title="Click to add your projects") .editable-icon.glyphicon.glyphicon-pencil if profile.projects && profile.projects.length @@ -367,7 +380,7 @@ block content p= project.name div!= marked(project.description) else if editing - h3.edit-label Add 3 projects + h3.edit-label(data-i18n="account_profile.projects_header") Add 3 projects ul.projects li.edit-example-text .project-image(style="background-image: url('/file/db/user/52a57252a89409700d0000d9/godzilla_babies.jpg')") @@ -384,28 +397,28 @@ block content form.editable-form .editable-icon.glyphicon.glyphicon-remove - h3 Projects (Top 3) - p Highlight your projects to amaze employers. + h3(data-i18n="account_profile.projects_header_2") Projects (Top 3) + p(data-i18n="account_profile.projects_blurb") Highlight your projects to amaze employers. for index in [0, 1, 2] - var project = (profile.projects || [])[index] || {}; .array-item.well.well-sm .form-group - label.control-label Project Name + label.control-label(data-i18n="account_profile.projects_name") Project Name input.form-control(type='text', maxlength='100', name="root[projects][#{index}][name]", value=project.name) - p.help-block What was the project called? + p.help-block(data-i18n="account_profile.projects_name_help") What was the project called? .form-group - label.control-label Description + label.control-label(data-i18n="account_profile.projects_description") Description textarea.form-control(rows=6, maxlength='400', data-schemaformat='markdown', name="root[projects][#{index}][description]")= project.description - p.help-block Briefly describe the project. + p.help-block(data-i18n="account_profile.projects_description_help") Briefly describe the project. .form-group - label.control-label Picture + label.control-label(data-i18n="account_profile.projects_picture") Picture .project-image(style="background-image: url('" + (src=project.picture ? "/file/" + project.picture : "/images/jquery.minicolors.png") + "')") input(type="hidden", name="root[projects][#{index}][picture]", value=project.picture) - p.help-block Upload a 230x115px or larger image showing off the project. + p.help-block(data-i18n="account_profile.projects_picture_help") Upload a 230x115px or larger image showing off the project. .form-group - label.control-label Link + label.control-label(data-i18n="account_profile.projects_link") Link input.form-control(type='url', pattern='^(ht|f)tp(s?)://[0-9a-zA-Z]([-.w]*[0-9a-zA-Z])*(:(0-9)*)*(/?)([a-zA-Z0-9-.?,\'/\+&%$#_=]*)?$', data-schemaformat='url', name="root[projects][#{index}][link]", value=project.link) - p.help-block Link to the project. + p.help-block(data-i18n="account_profile.projects_link_help") Link to the project. button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save else if allowedToViewJobProfile diff --git a/app/views/account/job_profile_view.coffee b/app/views/account/job_profile_view.coffee index e7a40c5c2..c38bc2d5c 100644 --- a/app/views/account/job_profile_view.coffee +++ b/app/views/account/job_profile_view.coffee @@ -97,13 +97,13 @@ module.exports = class JobProfileView extends CocoView _.pick @jobProfileTreema.data, (value, key) => key in @editableSettings -commonSkills = ['c#', 'java', 'javascript', 'php', 'android', 'jquery', 'python', 'c++', 'html', 'mysql', 'ios', 'asp.net', 'css', 'sql', 'iphone', '.net', 'objective-c', 'ruby-on-rails', 'c', 'ruby', 'sql-server', 'ajax', 'wpf', 'linux', 'database', 'django', 'vb.net', 'windows', 'facebook', 'r', 'html5', 'multithreading', 'ruby-on-rails-3', 'wordpress', 'winforms', 'node.js', 'spring', 'osx', 'performance', 'visual-studio-2010', 'oracle', 'swing', 'algorithm', 'git', 'linq', 'apache', 'web-services', 'perl', 'wcf', 'entity-framework', 'bash', 'visual-studio', 'sql-server-2008', 'hibernate', 'actionscript-3', 'angularjs', 'matlab', 'qt', 'ipad', 'sqlite', 'cocoa-touch', 'cocoa', 'flash', 'mongodb', 'codeigniter', 'jquery-ui', 'css3', 'tsql', 'google-maps', 'silverlight', 'security', 'delphi', 'vba', 'postgresql', 'jsp', 'shell', 'internet-explorer', 'google-app-engine', 'sockets', 'validation', 'scala', 'oop', 'unit-testing', 'xaml', 'parsing', 'twitter-bootstrap', 'google-chrome', 'http', 'magento', 'email', 'android-layout', 'flex', 'rest', 'maven', 'jsf', 'listview', 'date', 'winapi', 'windows-phone-7', 'facebook-graph-api', 'unix', 'url', 'c#-4.0', 'jquery-ajax', 'svn', 'symfony2', 'table', 'cakephp', 'firefox', 'ms-access', 'java-ee', 'jquery-mobile', 'python-2.7', 'tomcat', 'zend-framework', 'opencv', 'visual-c++', 'opengl', 'spring-mvc', 'sql-server-2005', 'authentication', 'search', 'xslt', 'servlets', 'pdf', 'animation', 'math', 'batch-file', 'excel-vba', 'iis', 'mod-rewrite', 'sharepoint', 'gwt', 'powershell', 'visual-studio-2012', 'haskell', 'grails', 'ubuntu', 'networking', 'nhibernate', 'design-patterns', 'testing', 'jpa', 'visual-studio-2008', 'core-data', 'user-interface', 'audio', 'backbone.js', 'gcc', 'mobile', 'design', 'activerecord', 'extjs', 'video', 'stored-procedures', 'optimization', 'drupal', 'image-processing', 'android-intent', 'logging', 'web-applications', 'razor', 'database-design', 'azure', 'vim', 'memory-management', 'model-view-controller', 'cordova', 'c++11', 'selenium', 'ssl', 'assembly', 'soap', 'boost', 'canvas', 'google-maps-api-3', 'netbeans', 'heroku', 'jsf-2', 'encryption', 'hadoop', 'linq-to-sql', 'dll', 'xpath', 'data-binding', 'windows-phone-8', 'phonegap', 'jdbc', 'python-3.x', 'twitter', 'mvvm', 'gui', 'web', 'jquery-plugins', 'numpy', 'deployment', 'ios7', 'emacs', 'knockout.js', 'graphics', 'joomla', 'unicode', 'windows-8', 'android-fragments', 'ant', 'command-line', 'version-control', 'yii', 'github', 'amazon-web-services', 'macros', 'ember.js', 'svg', 'opengl-es', 'django-models', 'solr', 'orm', 'blackberry', 'windows-7', 'ruby-on-rails-4', 'compiler', 'tcp', 'pdo', 'architecture', 'groovy', 'nginx', 'concurrency', 'paypal', 'iis-7', 'express', 'vbscript', 'google-chrome-extension', 'memory-leaks', 'rspec', 'actionscript', 'interface', 'fonts', 'oauth', 'ssh', 'tfs', 'junit', 'struts2', 'd3.js', 'coldfusion', '.net-4.0', 'jqgrid', 'asp-classic', 'https', 'plsql', 'stl', 'sharepoint-2010', 'asp.net-web-api', 'mysqli', 'sed', 'awk', 'internet-explorer-8', 'jboss', 'charts', 'scripting', 'matplotlib', 'laravel', 'clojure', 'entity-framework-4', 'intellij-idea', 'xml-parsing', 'sqlite3', '3d', 'io', 'mfc', 'devise', 'playframework', 'youtube', 'amazon-ec2', 'localization', 'cuda', 'jenkins', 'ssis', 'safari', 'doctrine2', 'vb6', 'amazon-s3', 'dojo', 'air', 'eclipse-plugin', 'android-asynctask', 'crystal-reports', 'cocos2d-iphone', 'dns', 'highcharts', 'ruby-on-rails-3.2', 'ado.net', 'sql-server-2008-r2', 'android-emulator', 'spring-security', 'cross-browser', 'oracle11g', 'bluetooth', 'f#', 'msbuild', 'drupal-7', 'google-apps-script', 'mercurial', 'xna', 'google-analytics', 'lua', 'parallel-processing', 'internationalization', 'java-me', 'mono', 'monotouch', 'android-ndk', 'lucene', 'kendo-ui', 'linux-kernel', 'terminal', 'phpmyadmin', 'makefile', 'ffmpeg', 'applet', 'active-directory', 'coffeescript', 'pandas', 'responsive-design', 'xhtml', 'silverlight-4.0', '.net-3.5', 'jaxb', 'ruby-on-rails-3.1', 'gps', 'geolocation', 'network-programming', 'windows-services', 'laravel-4', 'ggplot2', 'rss', 'webkit', 'functional-programming', 'wsdl', 'telerik', 'maven-2', 'cron', 'mapreduce', 'websocket', 'automation', 'windows-runtime', 'django-forms', 'tkinter', 'android-widget', 'android-activity', 'rubygems', 'content-management-system', 'doctrine', 'django-templates', 'gem', 'fluent-nhibernate', 'seo', 'meteor', 'serial-port', 'glassfish', 'documentation', 'cryptography', 'ef-code-first', 'extjs4', 'x86', 'wordpress-plugin', 'go', 'wix', 'linq-to-entities', 'oracle10g', 'cocos2d', 'selenium-webdriver', 'open-source', 'jtable', 'qt4', 'smtp', 'redis', 'jvm', 'openssl', 'timezone', 'nosql', 'erlang', 'playframework-2.0', 'machine-learning', 'mocking', 'unity3d', 'thread-safety', 'android-actionbar', 'jni', 'udp', 'jasper-reports', 'zend-framework2', 'apache2', 'internet-explorer-7', 'sqlalchemy', 'neo4j', 'ldap', 'jframe', 'youtube-api', 'filesystems', 'make', 'flask', 'gdb', 'cassandra', 'sms', 'g++', 'django-admin', 'push-notification', 'statistics', 'tinymce', 'locking', 'javafx', 'firefox-addon', 'fancybox', 'windows-phone', 'log4j', 'uikit', 'prolog', 'socket.io', 'icons', 'oauth-2.0', 'refactoring', 'sencha-touch', 'elasticsearch', 'symfony1', 'google-api', 'webserver', 'wpf-controls', 'microsoft-metro', 'gtk', 'flex4', 'three.js', 'gradle', 'centos', 'angularjs-directive', 'internet-explorer-9', 'sass', 'html5-canvas', 'interface-builder', 'programming-languages', 'gmail', 'jersey', 'twitter-bootstrap-3', 'arduino', 'requirejs', 'cmake', 'web-development', 'software-engineering', 'startups', 'entrepreneurship', 'social-media-marketing', 'writing', 'marketing', 'web-design', 'graphic-design', 'game-development', 'game-design', 'photoshop', 'illustrator', 'robotics', 'aws', 'devops', 'mathematica', 'bioinformatics', 'data-vis', 'ui', 'embedded-systems', 'codecombat'] +JobProfileView.commonSkills = commonSkills = ['c#', 'java', 'javascript', 'php', 'android', 'jquery', 'python', 'c++', 'html', 'mysql', 'ios', 'asp.net', 'css', 'sql', 'iphone', '.net', 'objective-c', 'ruby-on-rails', 'c', 'ruby', 'sql-server', 'ajax', 'wpf', 'linux', 'database', 'django', 'vb.net', 'windows', 'facebook', 'r', 'html5', 'multithreading', 'ruby-on-rails-3', 'wordpress', 'winforms', 'node.js', 'spring', 'osx', 'performance', 'visual-studio-2010', 'oracle', 'swing', 'algorithm', 'git', 'linq', 'apache', 'web-services', 'perl', 'wcf', 'entity-framework', 'bash', 'visual-studio', 'sql-server-2008', 'hibernate', 'actionscript-3', 'angularjs', 'matlab', 'qt', 'ipad', 'sqlite', 'cocoa-touch', 'cocoa', 'flash', 'mongodb', 'codeigniter', 'jquery-ui', 'css3', 'tsql', 'google-maps', 'silverlight', 'security', 'delphi', 'vba', 'postgresql', 'jsp', 'shell', 'internet-explorer', 'google-app-engine', 'sockets', 'validation', 'scala', 'oop', 'unit-testing', 'xaml', 'parsing', 'twitter-bootstrap', 'google-chrome', 'http', 'magento', 'email', 'android-layout', 'flex', 'rest', 'maven', 'jsf', 'listview', 'date', 'winapi', 'windows-phone-7', 'facebook-graph-api', 'unix', 'url', 'c#-4.0', 'jquery-ajax', 'svn', 'symfony2', 'table', 'cakephp', 'firefox', 'ms-access', 'java-ee', 'jquery-mobile', 'python-2.7', 'tomcat', 'zend-framework', 'opencv', 'visual-c++', 'opengl', 'spring-mvc', 'sql-server-2005', 'authentication', 'search', 'xslt', 'servlets', 'pdf', 'animation', 'math', 'batch-file', 'excel-vba', 'iis', 'mod-rewrite', 'sharepoint', 'gwt', 'powershell', 'visual-studio-2012', 'haskell', 'grails', 'ubuntu', 'networking', 'nhibernate', 'design-patterns', 'testing', 'jpa', 'visual-studio-2008', 'core-data', 'user-interface', 'audio', 'backbone.js', 'gcc', 'mobile', 'design', 'activerecord', 'extjs', 'video', 'stored-procedures', 'optimization', 'drupal', 'image-processing', 'android-intent', 'logging', 'web-applications', 'razor', 'database-design', 'azure', 'vim', 'memory-management', 'model-view-controller', 'cordova', 'c++11', 'selenium', 'ssl', 'assembly', 'soap', 'boost', 'canvas', 'google-maps-api-3', 'netbeans', 'heroku', 'jsf-2', 'encryption', 'hadoop', 'linq-to-sql', 'dll', 'xpath', 'data-binding', 'windows-phone-8', 'phonegap', 'jdbc', 'python-3.x', 'twitter', 'mvvm', 'gui', 'web', 'jquery-plugins', 'numpy', 'deployment', 'ios7', 'emacs', 'knockout.js', 'graphics', 'joomla', 'unicode', 'windows-8', 'android-fragments', 'ant', 'command-line', 'version-control', 'yii', 'github', 'amazon-web-services', 'macros', 'ember.js', 'svg', 'opengl-es', 'django-models', 'solr', 'orm', 'blackberry', 'windows-7', 'ruby-on-rails-4', 'compiler', 'tcp', 'pdo', 'architecture', 'groovy', 'nginx', 'concurrency', 'paypal', 'iis-7', 'express', 'vbscript', 'google-chrome-extension', 'memory-leaks', 'rspec', 'actionscript', 'interface', 'fonts', 'oauth', 'ssh', 'tfs', 'junit', 'struts2', 'd3.js', 'coldfusion', '.net-4.0', 'jqgrid', 'asp-classic', 'https', 'plsql', 'stl', 'sharepoint-2010', 'asp.net-web-api', 'mysqli', 'sed', 'awk', 'internet-explorer-8', 'jboss', 'charts', 'scripting', 'matplotlib', 'laravel', 'clojure', 'entity-framework-4', 'intellij-idea', 'xml-parsing', 'sqlite3', '3d', 'io', 'mfc', 'devise', 'playframework', 'youtube', 'amazon-ec2', 'localization', 'cuda', 'jenkins', 'ssis', 'safari', 'doctrine2', 'vb6', 'amazon-s3', 'dojo', 'air', 'eclipse-plugin', 'android-asynctask', 'crystal-reports', 'cocos2d-iphone', 'dns', 'highcharts', 'ruby-on-rails-3.2', 'ado.net', 'sql-server-2008-r2', 'android-emulator', 'spring-security', 'cross-browser', 'oracle11g', 'bluetooth', 'f#', 'msbuild', 'drupal-7', 'google-apps-script', 'mercurial', 'xna', 'google-analytics', 'lua', 'parallel-processing', 'internationalization', 'java-me', 'mono', 'monotouch', 'android-ndk', 'lucene', 'kendo-ui', 'linux-kernel', 'terminal', 'phpmyadmin', 'makefile', 'ffmpeg', 'applet', 'active-directory', 'coffeescript', 'pandas', 'responsive-design', 'xhtml', 'silverlight-4.0', '.net-3.5', 'jaxb', 'ruby-on-rails-3.1', 'gps', 'geolocation', 'network-programming', 'windows-services', 'laravel-4', 'ggplot2', 'rss', 'webkit', 'functional-programming', 'wsdl', 'telerik', 'maven-2', 'cron', 'mapreduce', 'websocket', 'automation', 'windows-runtime', 'django-forms', 'tkinter', 'android-widget', 'android-activity', 'rubygems', 'content-management-system', 'doctrine', 'django-templates', 'gem', 'fluent-nhibernate', 'seo', 'meteor', 'serial-port', 'glassfish', 'documentation', 'cryptography', 'ef-code-first', 'extjs4', 'x86', 'wordpress-plugin', 'go', 'wix', 'linq-to-entities', 'oracle10g', 'cocos2d', 'selenium-webdriver', 'open-source', 'jtable', 'qt4', 'smtp', 'redis', 'jvm', 'openssl', 'timezone', 'nosql', 'erlang', 'playframework-2.0', 'machine-learning', 'mocking', 'unity3d', 'thread-safety', 'android-actionbar', 'jni', 'udp', 'jasper-reports', 'zend-framework2', 'apache2', 'internet-explorer-7', 'sqlalchemy', 'neo4j', 'ldap', 'jframe', 'youtube-api', 'filesystems', 'make', 'flask', 'gdb', 'cassandra', 'sms', 'g++', 'django-admin', 'push-notification', 'statistics', 'tinymce', 'locking', 'javafx', 'firefox-addon', 'fancybox', 'windows-phone', 'log4j', 'uikit', 'prolog', 'socket.io', 'icons', 'oauth-2.0', 'refactoring', 'sencha-touch', 'elasticsearch', 'symfony1', 'google-api', 'webserver', 'wpf-controls', 'microsoft-metro', 'gtk', 'flex4', 'three.js', 'gradle', 'centos', 'angularjs-directive', 'internet-explorer-9', 'sass', 'html5-canvas', 'interface-builder', 'programming-languages', 'gmail', 'jersey', 'twitter-bootstrap-3', 'arduino', 'requirejs', 'cmake', 'web-development', 'software-engineering', 'startups', 'entrepreneurship', 'social-media-marketing', 'writing', 'marketing', 'web-design', 'graphic-design', 'game-development', 'game-design', 'photoshop', 'illustrator', 'robotics', 'aws', 'devops', 'mathematica', 'bioinformatics', 'data-vis', 'ui', 'embedded-systems', 'codecombat'] -commonLinkNames = ['GitHub', 'Facebook', 'Twitter', 'G+', 'LinkedIn', 'Personal Website', 'Blog'] +JobProfileView.commonLinkNames = commonLinkNames = ['GitHub', 'Facebook', 'Twitter', 'G+', 'LinkedIn', 'Personal Website', 'Blog'] -countries = ['Afghanistan', 'Albania', 'Algeria', 'American Samoa', 'Andorra', 'Angola', 'Anguilla', 'Antarctica', 'Antigua and Barbuda', 'Argentina', 'Armenia', 'Aruba', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivia', 'Bosnia and Herzegovina', 'Botswana', 'Brazil', 'Brunei Darussalam', 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Cayman Islands', 'Central African Republic', 'Chad', 'Chile', 'China', 'Christmas Island', 'Cocos (Keeling) Islands', 'Colombia', 'Comoros', 'Democratic Republic of the Congo (Kinshasa)', 'Congo, Republic of (Brazzaville)', 'Cook Islands', 'Costa Rica', 'Ivory Coast', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'East Timor', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Falkland Islands', 'Faroe Islands', 'Fiji', 'Finland', 'France', 'French Guiana', 'French Polynesia', 'French Southern Territories', 'Gabon', 'Gambia', 'Georgia', 'Germany', 'Ghana', 'Gibraltar', 'Great Britain', 'Greece', 'Greenland', 'Grenada', 'Guadeloupe', 'Guam', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Holy See', 'Honduras', 'Hong Kong', 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran', 'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kiribati', 'North Korea', 'South Korea', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Lao, People\'s Democratic Republic', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Macau', 'Macedonia, Rep. of', 'Madagascar', 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta', 'Marshall Islands', 'Martinique', 'Mauritania', 'Mauritius', 'Mayotte', 'Mexico', 'Micronesia, Federal States of', 'Moldova, Republic of', 'Monaco', 'Mongolia', 'Montenegro', 'Montserrat', 'Morocco', 'Mozambique', 'Myanmar, Burma', 'Namibia', 'Nauru', 'Nepal', 'Netherlands', 'Netherlands Antilles', 'New Caledonia', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'Niue', 'Northern Mariana Islands', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Palestinian territories', 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru', 'Philippines', 'Pitcairn Island', 'Poland', 'Portugal', 'Puerto Rico', 'Qatar', 'Reunion Island', 'Romania', 'Russian Federation', 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa', 'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovakia', 'Slovenia', 'Solomon Islands', 'Somalia', 'South Africa', 'South Sudan', 'Spain', 'Sri Lanka', 'Sudan', 'Suriname', 'Swaziland', 'Sweden', 'Switzerland', 'Syria, Syrian Arab Republic', 'Taiwan', 'Tajikistan', 'Tanzania; officially the United Republic of Tanzania', 'Thailand', 'Tibet', 'Timor-Leste', 'Togo', 'Tokelau', 'Tonga', 'Trinidad and Tobago', 'Tunisia', 'Turkey', 'Turkmenistan', 'Turks and Caicos Islands', 'Tuvalu', 'Uganda', 'Ukraine', 'United Arab Emirates', 'United Kingdom', 'USA', 'Uruguay', 'Uzbekistan', 'Vanuatu', 'Vatican City State', 'Venezuela', 'Vietnam', 'Virgin Islands (British)', 'Virgin Islands (U.S.)', 'Wallis and Futuna Islands', 'Western Sahara', 'Yemen', 'Zambia', 'Zimbabwe'] +JobProfileView.commonCountries = commonCountries = ['Afghanistan', 'Albania', 'Algeria', 'American Samoa', 'Andorra', 'Angola', 'Anguilla', 'Antarctica', 'Antigua and Barbuda', 'Argentina', 'Armenia', 'Aruba', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivia', 'Bosnia and Herzegovina', 'Botswana', 'Brazil', 'Brunei Darussalam', 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Cayman Islands', 'Central African Republic', 'Chad', 'Chile', 'China', 'Christmas Island', 'Cocos (Keeling) Islands', 'Colombia', 'Comoros', 'Democratic Republic of the Congo (Kinshasa)', 'Congo, Republic of (Brazzaville)', 'Cook Islands', 'Costa Rica', 'Ivory Coast', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'East Timor', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Falkland Islands', 'Faroe Islands', 'Fiji', 'Finland', 'France', 'French Guiana', 'French Polynesia', 'French Southern Territories', 'Gabon', 'Gambia', 'Georgia', 'Germany', 'Ghana', 'Gibraltar', 'Great Britain', 'Greece', 'Greenland', 'Grenada', 'Guadeloupe', 'Guam', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Holy See', 'Honduras', 'Hong Kong', 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran', 'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kiribati', 'North Korea', 'South Korea', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Lao, People\'s Democratic Republic', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Macau', 'Macedonia, Rep. of', 'Madagascar', 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta', 'Marshall Islands', 'Martinique', 'Mauritania', 'Mauritius', 'Mayotte', 'Mexico', 'Micronesia, Federal States of', 'Moldova, Republic of', 'Monaco', 'Mongolia', 'Montenegro', 'Montserrat', 'Morocco', 'Mozambique', 'Myanmar, Burma', 'Namibia', 'Nauru', 'Nepal', 'Netherlands', 'Netherlands Antilles', 'New Caledonia', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'Niue', 'Northern Mariana Islands', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Palestinian territories', 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru', 'Philippines', 'Pitcairn Island', 'Poland', 'Portugal', 'Puerto Rico', 'Qatar', 'Reunion Island', 'Romania', 'Russian Federation', 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa', 'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovakia', 'Slovenia', 'Solomon Islands', 'Somalia', 'South Africa', 'South Sudan', 'Spain', 'Sri Lanka', 'Sudan', 'Suriname', 'Swaziland', 'Sweden', 'Switzerland', 'Syria, Syrian Arab Republic', 'Taiwan', 'Tajikistan', 'Tanzania; officially the United Republic of Tanzania', 'Thailand', 'Tibet', 'Timor-Leste', 'Togo', 'Tokelau', 'Tonga', 'Trinidad and Tobago', 'Tunisia', 'Turkey', 'Turkmenistan', 'Turks and Caicos Islands', 'Tuvalu', 'Uganda', 'Ukraine', 'United Arab Emirates', 'United Kingdom', 'USA', 'Uruguay', 'Uzbekistan', 'Vanuatu', 'Vatican City State', 'Venezuela', 'Vietnam', 'Virgin Islands (British)', 'Virgin Islands (U.S.)', 'Wallis and Futuna Islands', 'Western Sahara', 'Yemen', 'Zambia', 'Zimbabwe'] -commonCities = ['Tokyo', 'Jakarta', 'Seoul', 'Delhi', 'Shanghai', 'Manila', 'Karachi', 'New York', 'Sao Paulo', 'Mexico City', 'Cairo', 'Beijing', 'Osaka', 'Mumbai (Bombay)', 'Guangzhou', 'Moscow', 'Los Angeles', 'Calcutta', 'Dhaka', 'Buenos Aires', 'Istanbul', 'Rio de Janeiro', 'Shenzhen', 'Lagos', 'Paris', 'Nagoya', 'Lima', 'Chicago', 'Kinshasa', 'Tianjin', 'Chennai', 'Bogota', 'Bengaluru', 'London', 'Taipei', 'Ho Chi Minh City (Saigon)', 'Dongguan', 'Hyderabad', 'Chengdu', 'Lahore', 'Johannesburg', 'Tehran', 'Essen', 'Bangkok', 'Hong Kong', 'Wuhan', 'Ahmedabad', 'Chongqung', 'Baghdad', 'Hangzhou', 'Toronto', 'Kuala Lumpur', 'Santiago', 'Dallas-Fort Worth', 'Quanzhou', 'Miami', 'Shenyang', 'Belo Horizonte', 'Philadelphia', 'Nanjing', 'Madrid', 'Houston', 'Xi\'an-Xianyang', 'Milan', 'Luanda', 'Pune', 'Singapore', 'Riyadh', 'Khartoum', 'Saint Petersburg', 'Atlanta', 'Surat', 'Washington', 'Bandung', 'Surabaya', 'Yangoon', 'Alexandria', 'Guadalajara', 'Harbin', 'Boston', 'Zhengzhou', 'Qingdao', 'Abidjan', 'Barcelona', 'Monterrey', 'Ankara', 'Suzhou', 'Phoenix-Mesa', 'Salvador', 'Porto Alegre', 'Rome', 'Accra', 'Sydney', 'Recife', 'Naples', 'Detroit', 'Dalian', 'Fuzhou', 'Medellin', 'San Francisco', 'Silicon Valley', 'Portland', 'Seattle', 'Austin', 'Denver', 'Boulder'] +JobProfileView.commonCities = commonCities = ['Tokyo', 'Jakarta', 'Seoul', 'Delhi', 'Shanghai', 'Manila', 'Karachi', 'New York', 'Sao Paulo', 'Mexico City', 'Cairo', 'Beijing', 'Osaka', 'Mumbai (Bombay)', 'Guangzhou', 'Moscow', 'Los Angeles', 'Calcutta', 'Dhaka', 'Buenos Aires', 'Istanbul', 'Rio de Janeiro', 'Shenzhen', 'Lagos', 'Paris', 'Nagoya', 'Lima', 'Chicago', 'Kinshasa', 'Tianjin', 'Chennai', 'Bogota', 'Bengaluru', 'London', 'Taipei', 'Ho Chi Minh City (Saigon)', 'Dongguan', 'Hyderabad', 'Chengdu', 'Lahore', 'Johannesburg', 'Tehran', 'Essen', 'Bangkok', 'Hong Kong', 'Wuhan', 'Ahmedabad', 'Chongqung', 'Baghdad', 'Hangzhou', 'Toronto', 'Kuala Lumpur', 'Santiago', 'Dallas-Fort Worth', 'Quanzhou', 'Miami', 'Shenyang', 'Belo Horizonte', 'Philadelphia', 'Nanjing', 'Madrid', 'Houston', 'Xi\'an-Xianyang', 'Milan', 'Luanda', 'Pune', 'Singapore', 'Riyadh', 'Khartoum', 'Saint Petersburg', 'Atlanta', 'Surat', 'Washington', 'Bandung', 'Surabaya', 'Yangoon', 'Alexandria', 'Guadalajara', 'Harbin', 'Boston', 'Zhengzhou', 'Qingdao', 'Abidjan', 'Barcelona', 'Monterrey', 'Ankara', 'Suzhou', 'Phoenix-Mesa', 'Salvador', 'Porto Alegre', 'Rome', 'Accra', 'Sydney', 'Recife', 'Naples', 'Detroit', 'Dalian', 'Fuzhou', 'Medellin', 'San Francisco', 'Silicon Valley', 'Portland', 'Seattle', 'Austin', 'Denver', 'Boulder'] autoFocus = true # Not working right now, possibly a Treema bower thing. @@ -128,5 +128,5 @@ class CityNode extends TreemaNode.nodeMap.string class CountryNode extends TreemaNode.nodeMap.string buildValueForEditing: (valEl) -> super(valEl) - valEl.find('input').autocomplete(source: countries, minLength: 1, delay: 0, autoFocus: autoFocus) + valEl.find('input').autocomplete(source: commonCountries, minLength: 1, delay: 0, autoFocus: autoFocus) valEl diff --git a/app/views/account/profile_view.coffee b/app/views/account/profile_view.coffee index 5e324b882..7fcc4501e 100644 --- a/app/views/account/profile_view.coffee +++ b/app/views/account/profile_view.coffee @@ -2,6 +2,8 @@ View = require 'views/kinds/RootView' template = require 'templates/account/profile' User = require 'models/User' JobProfileContactView = require 'views/modal/job_profile_contact_modal' +JobProfileView = require 'views/account/job_profile_view' +forms = require 'lib/forms' module.exports = class ProfileView extends View id: "profile-view" @@ -24,9 +26,11 @@ module.exports = class ProfileView extends View 'click .editable-profile a': 'onClickLinkWhileEditing' constructor: (options, @userID) -> + @userID ?= me.id @onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000 super options @uploadFilePath = "db/user/#{@userID}" + @highlightedContainers = [] if @userID is me.id @user = me else if me.isAdmin() or "employer" in me.get('permissions') @@ -34,9 +38,19 @@ module.exports = class ProfileView extends View @user.fetch() @listenTo @user, "sync", => @render() + else + @user = User.getByID(@userID) getRenderData: -> context = super() + context.jobProfileSchema = me.schema().properties.jobProfile + unless jobProfile = @user.get 'jobProfile' + jobProfile = {} + for prop, schema of context.jobProfileSchema.properties + jobProfile[prop] = _.clone schema.default if schema.default? + @user.set 'jobProfile', jobProfile + jobProfile.name ?= (@user.get('firstName') + ' ' + @user.get('lastName')).trim() if @user.get('firstName') + context.profile = jobProfile context.user = @user context.myProfile = @user.id is context.me.id context.allowedToViewJobProfile = me.isAdmin() or "employer" in me.get('permissions') or context.myProfile @@ -45,13 +59,9 @@ module.exports = class ProfileView extends View context.progress = @progress ? @updateProgress() @editing ?= context.progress < 0.8 context.editing = @editing - context.jobProfileSchema = me.schema().properties.jobProfile context.marked = marked context.moment = moment context.iconForLink = @iconForLink - unless jobProfile = @user.get 'jobProfile' - @user.set 'jobProfile', jobProfile = {} - jobProfile.name ?= (@user.get('firstName') + ' ' + @user.get('lastName')).trim() if @user.get('firstName') if links = jobProfile.links links = ($.extend(true, {}, link) for link in links) link.icon = @iconForLink link for link in links @@ -65,7 +75,18 @@ module.exports = class ProfileView extends View @$el.find('.middle-column').addClass('double-column') unless @editing @$el.find('.editable-display').attr('title', '') - _.defer => @progress = @updateProgress() + @initializeAutocomplete() + highlightNext = @highlightNext + justSavedSection = @$el.find('#' + @justSavedSectionID).addClass "just-saved" + _.defer => + @progress = @updateProgress highlightNext + _.delay -> + justSavedSection.removeClass "just-saved", duration: 1500, easing: 'easeOutQuad' + , 500 + + initializeAutocomplete: (container) -> + (container ? @$el).find('input[data-autocomplete]').each -> + $(@).autocomplete(source: JobProfileView[$(@).data('autocomplete')], minLength: parseInt($(@).data('autocomplete-min-length')), delay: 0, autoFocus: true) toggleEditing: -> @editing = not @editing @@ -115,21 +136,31 @@ module.exports = class ProfileView extends View onContactCandidate: (e) -> @openModalView new JobProfileContactView recipientID: @user.id - saveEdits: (e) -> - res = @user.validate() - if res? - console.error "Couldn't save because of validation errors:", res - # TODO: show some sort of problem message here - return + showErrors: (errors) -> + section = @$el.find '.saving' + console.error "Couldn't save because of validation errors:", errors + section.removeClass 'saving' + forms.clearFormAlerts section + # This is pretty lame, since we don't easily match which field had the error like forms.applyErrorsToForm can. + section.find('form').addClass('has-error').find('.save-section').before($("<span class='help-block error-help-block'>#{errors[0].message}</span>")) + + saveEdits: (highlightNext) -> + errors = @user.validate() + return @showErrors errors if errors jobProfile = @user.get('jobProfile') jobProfile.updated = (new Date()).toISOString() @user.set 'jobProfile', jobProfile return unless res = @user.save() - res.error -> - errors = JSON.parse(res.responseText) - # TODO: show some sort of problem message here + res.error => + return if @destroyed + @showErrors [message: res.responseText] res.success (model, response, options) => + return if @destroyed + @justSavedSectionID = @$el.find('.editable-section.saving').removeClass('saving').attr('id') + @highlightNext = highlightNext @render() + @highlightNext = false + @justSavedSectionID = null onEditProfilePhoto: (e) -> onSaving = => @@ -163,8 +194,8 @@ module.exports = class ProfileView extends View onSaved uploadingPath onEditSection: (e) -> - section = $(e.target).closest('.editable-section') - section.find('.editable-form').show() + section = $(e.target).closest('.editable-section').removeClass 'deemphasized' + section.find('.editable-form').show().find('select, input, textarea').first().focus() section.find('.editable-display').hide() @$el.find('.editable-section').not(section).addClass 'deemphasized' column = section.closest('.full-height-column') @@ -198,7 +229,10 @@ module.exports = class ProfileView extends View else unless child? child = parent[key] = {} parent = child - parent[key] = value + if key is 'link' and keyChain[0] is 'projects' and not value + delete parent[key] + else + parent[key] = value form.find('.editable-array').each -> key = $(@).data('property') unless rootPropertiesSeen[key] @@ -206,7 +240,7 @@ module.exports = class ProfileView extends View if section.hasClass('projects-container') and not section.find('.array-item').length jobProfile.projects = [] section.addClass 'saving' - @saveEdits() + @saveEdits true extractFieldKeyChain: (key) -> # "root[projects][0][name]" -> ["projects", "0", "name"] @@ -236,10 +270,11 @@ module.exports = class ProfileView extends View toRemove.unshift index $(arrayItems[emptyIndex]).remove() for emptyIndex in toRemove unless lastEmpty - clone = $(arrayItem).clone(true) + clone = $(arrayItem).clone(false) clone.find('input').each -> $(@).val('') clone.find('textarea').each -> $(@).text('') array.append clone + @initializeAutocomplete clone for arrayItem, index in array.find('.array-item') for input in $(arrayItem).find('input, textarea') $(input).attr('name', $(input).attr('name').replace(/\[\d+\]/, "[#{index}]")) @@ -247,7 +282,7 @@ module.exports = class ProfileView extends View onClickLinkWhileEditing: (e) -> e.preventDefault() - updateProgress: -> + updateProgress: (highlightNext) -> completed = 0 totalWeight = 0 next = null @@ -255,21 +290,26 @@ module.exports = class ProfileView extends View done = metric.fn() completed += metric.weight if done totalWeight += metric.weight - next = metric.name unless next or done + next = metric unless next or done progress = Math.round 100 * completed / totalWeight bar = @$el.find('.profile-completion-progress .progress-bar') bar.css 'width', "#{progress}%" text = "" + t = $.i18n.t if next and progress > 40 - text = "#{progress}% complete. Next: #{next}" + text = "#{progress}% #{t 'account_profile.complete'}. #{t 'account_profile.next'}: #{next.name}" else if next and progress > 30 - text = "#{progress}%. Next: #{next}" + text = "#{progress}%. #{t 'account_profile.next'}: #{next.name}" else if next and progress > 11 - text = "#{progress}%: #{next}" + text = "#{progress}%: #{next.name}" else if progress > 3 text = "#{progress}%" bar.text text bar.parent().toggle Boolean progress + if highlightNext and next?.container and not (next.container in @highlightedContainers) + @onEditSection target: next.container + @highlightedContainers.push next.container + $('#page-container').scrollTop 0 completed / totalWeight getProgressMetrics: -> @@ -278,17 +318,18 @@ module.exports = class ProfileView extends View exists = (field) -> -> jobProfile[field] modified = (field) -> -> jobProfile[field] and jobProfile[field] isnt schema.properties[field].default listStarted = (field, subfields) -> -> jobProfile[field]?.length and _.every subfields, (subfield) -> jobProfile[field][0][subfield] + t = $.i18n.t @progressMetrics = [ - {name: "city?", weight: 1, container: 'basic-info-container', fn: modified 'city'} - {name: "pick your country.", weight: 0, container: 'basic-info-container', fn: exists 'country'} - {name: "provide your name.", weight: 1, container: 'name-container', fn: modified 'name'} - {name: "summarize yourself at a glance.", weight: 2, container: 'short-description-container', fn: modified 'shortDescription'} - {name: "list at least five skills.", weight: 2, container: 'skills-container', fn: -> jobProfile.skills?.length >= 5} - {name: "describe the work you're looking for.", weight: 3, container: 'long-description-container', fn: modified 'longDescription'} - {name: "list your work experience.", weight: 3, container: 'work-container', fn: listStarted 'work', ['role', 'employer']} - {name: "recount your educational ordeals.", weight: 3, container: 'education-container', fn: listStarted 'education', ['degree', 'school']} - {name: "show off up to three projects you've worked on.", weight: 3, container: 'projects-container', fn: listStarted 'projects', ['name']} - {name: "add any personal or social links.", weight: 2, container: 'links-container', fn: listStarted 'links', ['link', 'name']} - {name: "add an optional professional photo.", weight: 2, container: 'profile-photo-container', fn: modified 'photoURL'} - {name: "mark yourself open to offers to show up in searches.", weight: 1, fn: modified 'active'} + {name: t('account_profile.next_city'), weight: 1, container: '#basic-info-container', fn: modified 'city'} + {name: t('account_profile.next_country'), weight: 0, container: '#basic-info-container', fn: exists 'country'} + {name: t('account_profile.next_name'), weight: 1, container: '#name-container', fn: modified 'name'} + {name: t('account_profile.next_short_description'), weight: 2, container: '#short-description-container', fn: modified 'shortDescription'} + {name: t('account_profile.next_skills'), weight: 2, container: '#skills-container', fn: -> jobProfile.skills?.length >= 5} + {name: t('account_profile.next_long_description'), weight: 3, container: '#long-description-container', fn: modified 'longDescription'} + {name: t('account_profile.next_work'), weight: 3, container: '#work-container', fn: listStarted 'work', ['role', 'employer']} + {name: t('account_profile.next_education'), weight: 3, container: '#education-container', fn: listStarted 'education', ['degree', 'school']} + {name: t('account_profile.next_projects'), weight: 3, container: '#projects-container', fn: listStarted 'projects', ['name']} + {name: t('account_profile.next_links'), weight: 2, container: '#links-container', fn: listStarted 'links', ['link', 'name']} + {name: t('account_profile.next_photo'), weight: 2, container: '#profile-photo-container', fn: modified 'photoURL'} + {name: t('account_profile.next_active'), weight: 1, fn: modified 'active'} ]