Skip to content

Instantly share code, notes, and snippets.

@caseyWebb
Last active January 13, 2017 19:54
Show Gist options
  • Save caseyWebb/5b719973f7df3e9ae94705b521d86264 to your computer and use it in GitHub Desktop.
Save caseyWebb/5b719973f7df3e9ae94705b521d86264 to your computer and use it in GitHub Desktop.
Link-List Refactor
'use strict'
let _; const { each, map, some, every } = _ = require('lodash')
const ko = require('knockout')
const $ = require('jquery')
const Query = require('ko-querystring').default
module.exports = class LinkList {
constructor({
sections,
select2 = false,
topComponent,
bottomComponent
}) {
this.query = new Query({
search: '',
finder: []
})
this.subs = [
this.query.search.subscribe(() => $('html, body').animate({ scrollTop: 0 }, 'fast'))
]
this.select2 = select2
if (topComponent) {
this.topComponent = true
ko.components.register('top-component', topComponent)
}
if (bottomComponent) {
this.bottomComponent = true
ko.components.register('bottom-component', bottomComponent)
}
this.sections = _.map(sections, (s) => new Section(s, this.query.search))
this.allHidden = ko.pureComputed(() => !_.some(this.sections, (s) => s.visible()))
}
get navItems() {
return map(this.sections, 'text')
}
get keywords() {
return _(this.sections)
.flatMap((s) => s.links)
.flatMap((l) => l.keywords)
.value()
}
dispose() {
if (this.topComponent) {
ko.components.unregister('top-component')
}
if (this.bottomComponent) {
ko.components.unregister('bottom-component')
}
each(this.subs, (s) => s.dispose())
}
}
class Section {
constructor({
text,
links
}, search) {
this.text = text
this.id = this.text.replace(/\s+/i, '-')
this.links = map(links, (l) => new Link(l, search, getKeywords(this.text.split(/\W+/))))
this.visible = ko.pureComputed(() => some(this.links, (l) => l.visible()))
}
}
class Link {
constructor({
text,
url,
external = false,
keywords = [],
help = false
}, search, sectionKeywords) {
this.text = text
this.url = url
this.external = external
this.help = help
this.keywords = getKeywords(keywords.concat(sectionKeywords).concat(this.text.split(/\W+/)))
this.visible = ko.pureComputed(() =>
every(search().toLowerCase().split(/\W+/), (token) =>
_.some(this.keywords, (k) =>
_.includes(k, token))))
}
}
function getKeywords(words) {
return _(words)
.uniq()
.without('a', 'an', 'and', 'all', 'are', 'be', 'by', 'do', 'ed', 'for', 'if', 'in', 'me', 'of', 'or', 'to', 'you', 'your')
.invokeMap('toLowerCase')
.value()
}
'use strict'
const API = ApiBase + 'InstructorUsers/GetCustomFieldNames'
const ko = require('knockout')
const $ = require('jquery')
const _ = require('lodash')
const breadcrumbs = require('components/breadcrumbs')
const QueryCache = require('utils/query-cache')
const api = require('api')
const find = (w1, w2) => typeof w2 === 'string' && typeof w1 === 'string'
? w1.toLowerCase().indexOf(w2.toLowerCase()) !== -1
: false
const addFields = (words, userCustomFields) => {
// Change the Learner-Custom-Fields to their appropriate names
if (words.indexOf('Learner-Custom-Fields') !== -1) {
words.splice(words.indexOf('Learner-Custom-Fields'), 1)
words = words.concat(userCustomFields)
}
return words
}
module.exports = class {
constructor(params) {
this.ready = ko.observable(false)
const cache = QueryCache.exists(API) ? QueryCache.getCache(API) : new QueryCache(API)
new Promise((resolve) => cache.hasQuery({})
? resolve(cache.getQuery({}).metadata)
: api.get(API).then((response) => {
cache.setQuery({ query: {}, response, getMetadata: (r) => r, getResources: (r) => r })
resolve(response)
})).then((res) => {
const userCustomFields = res
const pages = params.pages.list
this.subs = []
this.query = params.pages.ctx.$parent ? params.pages.ctx.$parent.query : params.pages.ctx.query
this.searchByFields = params.pages.fieldNames || false // Used as boolean
if (this.searchByFields) this.types = this.searchByFields
this.select2 = params.pages.select2 === true
this.showAll = params.pages.showAll || this.searchByFields
this.query.setDefaults({
search: '',
finder: []
})
this.searchText = this.query.get('search')
this.subs.push(this.searchText.subscribe(() => $('html, body').animate({ scrollTop: 0 }, 'fast')))
if (params.pages.bcs) breadcrumbs.set(params.pages.bcs)
if (params.pages.topComponent) {
this.topComponent = params.pages.topComponent
if (!ko.components.isRegistered('top-component')) {
ko.components.register('top-component', this.topComponent)
}
}
if (params.pages.bottomComponent) {
this.bottomComponent = params.pages.bottomComponent
if (!ko.components.isRegistered('top-component')) {
ko.components.register('bottom-component', this.bottomComponent)
}
}
// Hide 'Background Tasks' on cloud sites except when logged in as 'userid=0' (administrator)
if (document.location.hostname.toLowerCase().indexOf('.universitysite.com') > -1
&& window.globals.CurrentUser.ID() !== 1)
_.each(pages, (page) => _.remove(page.links, (link) => link.url == 'background-tasks'))
this.navItems = _.map(pages, (p) => p.id ? { text: p.text, anchor: p.id } : p.text)
this.numTerms = ko.pureComputed(() => this.query.get('finder')() ? this.query.get('finder')().length : 0)
this.finderEmpty = ko.pureComputed(() => !this.query.get('finder')() || this.numTerms() === 0)
this.finderHasAll = ko.pureComputed(() => this.query.get('finder')() && _.find(this.query.get('finder')(), (s) => s.id === 'All'))
this.searchEmpty = ko.pureComputed(() => !this.searchText() || this.searchText() === '')
this.sections = _.map(pages, (page) => {
page.links = _.map(page.links, (link) => {
link.showAll = ko.observable(false)
link.fields = []
if (!link.keywords) link.keywords = []
link.keywords.push({ text: 'Heading', shouldShow: false, words: [page.text] })
_.each(link.keywords, (k) => {
if (!k.text) k = { text: 'Keyword', words: [k] }
Array.prototype.push.apply(link.fields, _.map(addFields(k.words, userCustomFields), (w) => {
k.shouldShow === false || (k.shouldShow = true)
return {
text: `${w} (${k.text})`,
help: k.help,
shouldShow: k.shouldShow,
field: w,
visible: ko.pureComputed(() => this.query.get('finder')() &&
this.searchByFields
? this.numTerms() > 0 && _.find(this.query.get('finder')(), (s) =>
s.id.indexOf('-') === -1 ? find(w, s.id) : w === s.id)
: !this.searchEmpty() && find(w, this.searchText())),
showAll: link.showAll
}}))
})
// how many fields are visible
link.visibleFields = ko.pureComputed(() => _.filter(link.fields, (f) => f.visible()))
// How many unique fields are visible
link.uniqFields = ko.pureComputed(() => {
const arr = []
_.each(link.visibleFields(), (f) =>
!_.find(arr, (a) => a.field === f.field) && arr.push(f))
return arr
})
link.matchSearch = ko.pureComputed(() => !this.searchEmpty() && find(link.text, this.query.get('search')()))
link.matchFinder = ko.pureComputed(() => !this.finderEmpty() && link.uniqFields().length >= this.numTerms())
link.visible = ko.pureComputed(() =>
this.searchByFields
? (this.searchEmpty() && this.finderEmpty())
|| (this.finderEmpty() && link.matchSearch())
|| (this.searchEmpty() && link.matchFinder())
|| (link.matchFinder() && link.matchSearch())
|| this.finderHasAll()
: this.searchEmpty() || link.visibleFields().length > 0 || link.matchSearch())
link.words = []
_.each(link.fields, (f) => {
Array.prototype.push.apply(link.words, f.text.split(' '))
})
return link
})
page.visible = ko.pureComputed(() => _.findIndex(page.links, (l) => l.visible()) >= 0)
return page
})
this.visibleSections = ko.pureComputed(() => _.filter(this.sections, (s) => s.visible()).length)
this.keywords = []
_.each(this.sections, (p) => _.each(p.links, (l) =>
Array.prototype.push.apply(this.keywords, addFields(l.words, userCustomFields))))
this.keywords = _(this.keywords).sortBy().uniq()
.filter((w) => ((w.charCodeAt(0) > 96 && w.charCodeAt(0) < 123) || (w.charCodeAt(0) > 64 && w.charCodeAt(0) < 91))
&& w.search('<') === -1)
.map((w) => w.replace('.', ''))
.reject((w) => _.includes(['a', 'an', 'and', 'all', 'are', 'be', 'by', 'do', 'ed', 'for', 'if', 'in', 'me', 'of', 'or', 'to', 'you', 'your'], w))
.map((w) => {return {
id: w,
text: w
}}).toArray().value()
this.ready(true)
})
}
dispose() {
if (ko.components.isRegistered('top-component')) ko.components.unregister('top-component')
if (ko.components.isRegistered('bottom-component')) ko.components.unregister('bottom-component')
_.each(this.subs, (s) => s.dispose())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment