Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
41f1e9d3
Commit
41f1e9d3
authored
Jul 29, 2012
by
Rocky Duan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
forgot to include files & tiny styling fix
parent
25e47f49
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1141 additions
and
6 deletions
+1141
-6
common/static/js/vendor/jquery.autocomplete.js
+1092
-0
lms/static/css/vendor/jquery.autocomplete.css
+36
-0
lms/static/sass/_discussion.scss
+13
-6
No files found.
common/static/js/vendor/jquery.autocomplete.js
0 → 100644
View file @
41f1e9d3
/**
* @fileOverview jquery-autocomplete, the jQuery Autocompleter
* @author <a href="mailto:dylan@dyve.net">Dylan Verheul</a>
* @requires jQuery 1.6+
*
* Copyright 2005-2012, Dylan Verheul
*
* Use under either MIT, GPL or Apache 2.0. See LICENSE.txt
*
* Project home: https://github.com/dyve/jquery-autocomplete
*/
(
function
(
$
)
{
"use strict"
;
/**
* jQuery autocomplete plugin
* @param {object|string} options
* @returns (object} jQuery object
*/
$
.
fn
.
autocomplete
=
function
(
options
)
{
var
url
;
if
(
arguments
.
length
>
1
)
{
url
=
options
;
options
=
arguments
[
1
];
options
.
url
=
url
;
}
else
if
(
typeof
options
===
'string'
)
{
url
=
options
;
options
=
{
url
:
url
};
}
var
opts
=
$
.
extend
({},
$
.
fn
.
autocomplete
.
defaults
,
options
);
return
this
.
each
(
function
()
{
var
$this
=
$
(
this
);
$this
.
data
(
'autocompleter'
,
new
$
.
Autocompleter
(
$this
,
$
.
meta
?
$
.
extend
({},
opts
,
$this
.
data
())
:
opts
));
});
};
/**
* Store default options
* @type {object}
*/
$
.
fn
.
autocomplete
.
defaults
=
{
inputClass
:
'acInput'
,
loadingClass
:
'acLoading'
,
resultsClass
:
'acResults'
,
selectClass
:
'acSelect'
,
queryParamName
:
'q'
,
extraParams
:
{},
remoteDataType
:
false
,
lineSeparator
:
'
\
n'
,
cellSeparator
:
'|'
,
minChars
:
2
,
maxItemsToShow
:
10
,
delay
:
400
,
useCache
:
true
,
maxCacheLength
:
10
,
matchSubset
:
true
,
matchCase
:
false
,
matchInside
:
true
,
mustMatch
:
false
,
selectFirst
:
false
,
selectOnly
:
false
,
showResult
:
null
,
preventDefaultReturn
:
true
,
preventDefaultTab
:
false
,
autoFill
:
false
,
filterResults
:
true
,
sortResults
:
true
,
sortFunction
:
null
,
onItemSelect
:
null
,
onNoMatch
:
null
,
onFinish
:
null
,
matchStringConverter
:
null
,
beforeUseConverter
:
null
,
autoWidth
:
'min-width'
,
useDelimiter
:
false
,
delimiterChar
:
','
,
delimiterKeyCode
:
188
,
processData
:
null
,
onError
:
null
};
/**
* Sanitize result
* @param {Object} result
* @returns {Object} object with members value (String) and data (Object)
* @private
*/
var
sanitizeResult
=
function
(
result
)
{
var
value
,
data
;
var
type
=
typeof
result
;
if
(
type
===
'string'
)
{
value
=
result
;
data
=
{};
}
else
if
(
$
.
isArray
(
result
))
{
value
=
result
[
0
];
data
=
result
.
slice
(
1
);
}
else
if
(
type
===
'object'
)
{
value
=
result
.
value
;
data
=
result
.
data
;
}
value
=
String
(
value
);
if
(
typeof
data
!==
'object'
)
{
data
=
{};
}
return
{
value
:
value
,
data
:
data
};
};
/**
* Sanitize integer
* @param {mixed} value
* @param {Object} options
* @returns {Number} integer
* @private
*/
var
sanitizeInteger
=
function
(
value
,
stdValue
,
options
)
{
var
num
=
parseInt
(
value
,
10
);
options
=
options
||
{};
if
(
isNaN
(
num
)
||
(
options
.
min
&&
num
<
options
.
min
))
{
num
=
stdValue
;
}
return
num
;
};
/**
* Create partial url for a name/value pair
*/
var
makeUrlParam
=
function
(
name
,
value
)
{
return
[
name
,
encodeURIComponent
(
value
)].
join
(
'='
);
};
/**
* Build an url
* @param {string} url Base url
* @param {object} [params] Dictionary of parameters
*/
var
makeUrl
=
function
(
url
,
params
)
{
var
urlAppend
=
[];
$
.
each
(
params
,
function
(
index
,
value
)
{
urlAppend
.
push
(
makeUrlParam
(
index
,
value
));
});
if
(
urlAppend
.
length
)
{
url
+=
url
.
indexOf
(
'?'
)
===
-
1
?
'?'
:
'&'
;
url
+=
urlAppend
.
join
(
'&'
);
}
return
url
;
};
/**
* Default sort filter
* @param {object} a
* @param {object} b
* @param {boolean} matchCase
* @returns {number}
*/
var
sortValueAlpha
=
function
(
a
,
b
,
matchCase
)
{
a
=
String
(
a
.
value
);
b
=
String
(
b
.
value
);
if
(
!
matchCase
)
{
a
=
a
.
toLowerCase
();
b
=
b
.
toLowerCase
();
}
if
(
a
>
b
)
{
return
1
;
}
if
(
a
<
b
)
{
return
-
1
;
}
return
0
;
};
/**
* Parse data received in text format
* @param {string} text Plain text input
* @param {string} lineSeparator String that separates lines
* @param {string} cellSeparator String that separates cells
* @returns {array} Array of autocomplete data objects
*/
var
plainTextParser
=
function
(
text
,
lineSeparator
,
cellSeparator
)
{
var
results
=
[];
var
i
,
j
,
data
,
line
,
value
,
lines
;
// Be nice, fix linebreaks before splitting on lineSeparator
lines
=
String
(
text
).
replace
(
'
\
r
\
n'
,
'
\
n'
).
split
(
lineSeparator
);
for
(
i
=
0
;
i
<
lines
.
length
;
i
++
)
{
line
=
lines
[
i
].
split
(
cellSeparator
);
data
=
[];
for
(
j
=
0
;
j
<
line
.
length
;
j
++
)
{
data
.
push
(
decodeURIComponent
(
line
[
j
]));
}
value
=
data
.
shift
();
results
.
push
({
value
:
value
,
data
:
data
});
}
return
results
;
};
/**
* Autocompleter class
* @param {object} $elem jQuery object with one input tag
* @param {object} options Settings
* @constructor
*/
$
.
Autocompleter
=
function
(
$elem
,
options
)
{
/**
* Assert parameters
*/
if
(
!
$elem
||
!
(
$elem
instanceof
$
)
||
$elem
.
length
!==
1
||
$elem
.
get
(
0
).
tagName
.
toUpperCase
()
!==
'INPUT'
)
{
throw
new
Error
(
'Invalid parameter for jquery.Autocompleter, jQuery object with one element with INPUT tag expected.'
);
}
/**
* @constant Link to this instance
* @type object
* @private
*/
var
self
=
this
;
/**
* @property {object} Options for this instance
* @public
*/
this
.
options
=
options
;
/**
* @property object Cached data for this instance
* @private
*/
this
.
cacheData_
=
{};
/**
* @property {number} Number of cached data items
* @private
*/
this
.
cacheLength_
=
0
;
/**
* @property {string} Class name to mark selected item
* @private
*/
this
.
selectClass_
=
'jquery-autocomplete-selected-item'
;
/**
* @property {number} Handler to activation timeout
* @private
*/
this
.
keyTimeout_
=
null
;
/**
* @property {number} Handler to finish timeout
* @private
*/
this
.
finishTimeout_
=
null
;
/**
* @property {number} Last key pressed in the input field (store for behavior)
* @private
*/
this
.
lastKeyPressed_
=
null
;
/**
* @property {string} Last value processed by the autocompleter
* @private
*/
this
.
lastProcessedValue_
=
null
;
/**
* @property {string} Last value selected by the user
* @private
*/
this
.
lastSelectedValue_
=
null
;
/**
* @property {boolean} Is this autocompleter active (showing results)?
* @see showResults
* @private
*/
this
.
active_
=
false
;
/**
* @property {boolean} Is this autocompleter allowed to finish on blur?
* @private
*/
this
.
finishOnBlur_
=
true
;
/**
* Sanitize options
*/
this
.
options
.
minChars
=
sanitizeInteger
(
this
.
options
.
minChars
,
$
.
fn
.
autocomplete
.
defaults
.
minChars
,
{
min
:
1
});
this
.
options
.
maxItemsToShow
=
sanitizeInteger
(
this
.
options
.
maxItemsToShow
,
$
.
fn
.
autocomplete
.
defaults
.
maxItemsToShow
,
{
min
:
0
});
this
.
options
.
maxCacheLength
=
sanitizeInteger
(
this
.
options
.
maxCacheLength
,
$
.
fn
.
autocomplete
.
defaults
.
maxCacheLength
,
{
min
:
1
});
this
.
options
.
delay
=
sanitizeInteger
(
this
.
options
.
delay
,
$
.
fn
.
autocomplete
.
defaults
.
delay
,
{
min
:
0
});
/**
* Init DOM elements repository
*/
this
.
dom
=
{};
/**
* Store the input element we're attached to in the repository
*/
this
.
dom
.
$elem
=
$elem
;
/**
* Switch off the native autocomplete and add the input class
*/
this
.
dom
.
$elem
.
attr
(
'autocomplete'
,
'off'
).
addClass
(
this
.
options
.
inputClass
);
/**
* Create DOM element to hold results, and force absolute position
*/
this
.
dom
.
$results
=
$
(
'<div></div>'
).
hide
().
addClass
(
this
.
options
.
resultsClass
).
css
({
position
:
'absolute'
});
$
(
'body'
).
append
(
this
.
dom
.
$results
);
/**
* Attach keyboard monitoring to $elem
*/
$elem
.
keydown
(
function
(
e
)
{
self
.
lastKeyPressed_
=
e
.
keyCode
;
switch
(
self
.
lastKeyPressed_
)
{
case
self
.
options
.
delimiterKeyCode
:
// comma = 188
if
(
self
.
options
.
useDelimiter
&&
self
.
active_
)
{
self
.
selectCurrent
();
}
break
;
// ignore navigational & special keys
case
35
:
// end
case
36
:
// home
case
16
:
// shift
case
17
:
// ctrl
case
18
:
// alt
case
37
:
// left
case
39
:
// right
break
;
case
38
:
// up
e
.
preventDefault
();
if
(
self
.
active_
)
{
self
.
focusPrev
();
}
else
{
self
.
activate
();
}
return
false
;
case
40
:
// down
e
.
preventDefault
();
if
(
self
.
active_
)
{
self
.
focusNext
();
}
else
{
self
.
activate
();
}
return
false
;
case
9
:
// tab
if
(
self
.
active_
)
{
self
.
selectCurrent
();
if
(
self
.
options
.
preventDefaultTab
)
{
e
.
preventDefault
();
return
false
;
}
}
break
;
case
13
:
// return
if
(
self
.
active_
)
{
self
.
selectCurrent
();
if
(
self
.
options
.
preventDefaultReturn
)
{
e
.
preventDefault
();
return
false
;
}
}
break
;
case
27
:
// escape
if
(
self
.
active_
)
{
e
.
preventDefault
();
self
.
deactivate
(
true
);
return
false
;
}
break
;
default
:
self
.
activate
();
}
});
/**
* Finish on blur event
* Use a timeout because instant blur gives race conditions
*/
$elem
.
blur
(
function
()
{
if
(
self
.
finishOnBlur_
)
{
self
.
finishTimeout_
=
setTimeout
(
function
()
{
self
.
deactivate
(
true
);
},
200
);
}
});
};
/**
* Position output DOM elements
* @private
*/
$
.
Autocompleter
.
prototype
.
position
=
function
()
{
var
offset
=
this
.
dom
.
$elem
.
offset
();
this
.
dom
.
$results
.
css
({
top
:
offset
.
top
+
this
.
dom
.
$elem
.
outerHeight
(),
left
:
offset
.
left
});
};
/**
* Read from cache
* @private
*/
$
.
Autocompleter
.
prototype
.
cacheRead
=
function
(
filter
)
{
var
filterLength
,
searchLength
,
search
,
maxPos
,
pos
;
if
(
this
.
options
.
useCache
)
{
filter
=
String
(
filter
);
filterLength
=
filter
.
length
;
if
(
this
.
options
.
matchSubset
)
{
searchLength
=
1
;
}
else
{
searchLength
=
filterLength
;
}
while
(
searchLength
<=
filterLength
)
{
if
(
this
.
options
.
matchInside
)
{
maxPos
=
filterLength
-
searchLength
;
}
else
{
maxPos
=
0
;
}
pos
=
0
;
while
(
pos
<=
maxPos
)
{
search
=
filter
.
substr
(
0
,
searchLength
);
if
(
this
.
cacheData_
[
search
]
!==
undefined
)
{
return
this
.
cacheData_
[
search
];
}
pos
++
;
}
searchLength
++
;
}
}
return
false
;
};
/**
* Write to cache
* @private
*/
$
.
Autocompleter
.
prototype
.
cacheWrite
=
function
(
filter
,
data
)
{
if
(
this
.
options
.
useCache
)
{
if
(
this
.
cacheLength_
>=
this
.
options
.
maxCacheLength
)
{
this
.
cacheFlush
();
}
filter
=
String
(
filter
);
if
(
this
.
cacheData_
[
filter
]
!==
undefined
)
{
this
.
cacheLength_
++
;
}
this
.
cacheData_
[
filter
]
=
data
;
return
this
.
cacheData_
[
filter
];
}
return
false
;
};
/**
* Flush cache
* @public
*/
$
.
Autocompleter
.
prototype
.
cacheFlush
=
function
()
{
this
.
cacheData_
=
{};
this
.
cacheLength_
=
0
;
};
/**
* Call hook
* Note that all called hooks are passed the autocompleter object
* @param {string} hook
* @param data
* @returns Result of called hook, false if hook is undefined
*/
$
.
Autocompleter
.
prototype
.
callHook
=
function
(
hook
,
data
)
{
var
f
=
this
.
options
[
hook
];
if
(
f
&&
$
.
isFunction
(
f
))
{
return
f
(
data
,
this
);
}
return
false
;
};
/**
* Set timeout to activate autocompleter
*/
$
.
Autocompleter
.
prototype
.
activate
=
function
()
{
var
self
=
this
;
if
(
this
.
keyTimeout_
)
{
clearTimeout
(
this
.
keyTimeout_
);
}
this
.
keyTimeout_
=
setTimeout
(
function
()
{
self
.
activateNow
();
},
this
.
options
.
delay
);
};
/**
* Activate autocompleter immediately
*/
$
.
Autocompleter
.
prototype
.
activateNow
=
function
()
{
var
value
=
this
.
beforeUseConverter
(
this
.
dom
.
$elem
.
val
());
if
(
value
!==
this
.
lastProcessedValue_
&&
value
!==
this
.
lastSelectedValue_
)
{
this
.
fetchData
(
value
);
}
};
/**
* Get autocomplete data for a given value
* @param {string} value Value to base autocompletion on
* @private
*/
$
.
Autocompleter
.
prototype
.
fetchData
=
function
(
value
)
{
var
self
=
this
;
var
processResults
=
function
(
results
,
filter
)
{
if
(
self
.
options
.
processData
)
{
results
=
self
.
options
.
processData
(
results
);
}
self
.
showResults
(
self
.
filterResults
(
results
,
filter
),
filter
);
};
this
.
lastProcessedValue_
=
value
;
if
(
value
.
length
<
this
.
options
.
minChars
)
{
processResults
([],
value
);
}
else
if
(
this
.
options
.
data
)
{
processResults
(
this
.
options
.
data
,
value
);
}
else
{
this
.
fetchRemoteData
(
value
,
function
(
remoteData
)
{
console
.
log
(
remoteData
);
processResults
(
remoteData
,
value
);
});
}
};
/**
* Get remote autocomplete data for a given value
* @param {string} filter The filter to base remote data on
* @param {function} callback The function to call after data retrieval
* @private
*/
$
.
Autocompleter
.
prototype
.
fetchRemoteData
=
function
(
filter
,
callback
)
{
var
data
=
this
.
cacheRead
(
filter
);
if
(
data
)
{
callback
(
data
);
}
else
{
var
self
=
this
;
var
dataType
=
self
.
options
.
remoteDataType
===
'json'
?
'json'
:
'text'
;
var
ajaxCallback
=
function
(
data
)
{
var
parsed
=
false
;
if
(
data
!==
false
)
{
parsed
=
self
.
parseRemoteData
(
data
);
self
.
cacheWrite
(
filter
,
parsed
);
}
self
.
dom
.
$elem
.
removeClass
(
self
.
options
.
loadingClass
);
callback
(
parsed
);
};
this
.
dom
.
$elem
.
addClass
(
this
.
options
.
loadingClass
);
$
.
ajax
({
url
:
this
.
makeUrl
(
filter
),
success
:
ajaxCallback
,
error
:
function
(
jqXHR
,
textStatus
,
errorThrown
)
{
if
(
$
.
isFunction
(
self
.
options
.
onError
))
{
self
.
options
.
onError
(
jqXHR
,
textStatus
,
errorThrown
);
}
else
{
ajaxCallback
(
false
);
}
},
dataType
:
dataType
});
}
};
/**
* Create or update an extra parameter for the remote request
* @param {string} name Parameter name
* @param {string} value Parameter value
* @public
*/
$
.
Autocompleter
.
prototype
.
setExtraParam
=
function
(
name
,
value
)
{
var
index
=
$
.
trim
(
String
(
name
));
if
(
index
)
{
if
(
!
this
.
options
.
extraParams
)
{
this
.
options
.
extraParams
=
{};
}
if
(
this
.
options
.
extraParams
[
index
]
!==
value
)
{
this
.
options
.
extraParams
[
index
]
=
value
;
this
.
cacheFlush
();
}
}
};
/**
* Build the url for a remote request
* If options.queryParamName === false, append query to url instead of using a GET parameter
* @param {string} param The value parameter to pass to the backend
* @returns {string} The finished url with parameters
*/
$
.
Autocompleter
.
prototype
.
makeUrl
=
function
(
param
)
{
var
self
=
this
;
var
url
=
this
.
options
.
url
;
var
params
=
$
.
extend
({},
this
.
options
.
extraParams
);
if
(
this
.
options
.
queryParamName
===
false
)
{
url
+=
encodeURIComponent
(
param
);
}
else
{
params
[
this
.
options
.
queryParamName
]
=
param
;
}
return
makeUrl
(
url
,
params
);
};
/**
* Parse data received from server
* @param remoteData Data received from remote server
* @returns {array} Parsed data
*/
$
.
Autocompleter
.
prototype
.
parseRemoteData
=
function
(
remoteData
)
{
var
remoteDataType
;
var
data
=
remoteData
;
if
(
this
.
options
.
remoteDataType
===
'json'
)
{
remoteDataType
=
typeof
(
remoteData
);
switch
(
remoteDataType
)
{
case
'object'
:
data
=
remoteData
;
break
;
case
'string'
:
data
=
$
.
parseJSON
(
remoteData
);
break
;
default
:
throw
new
Error
(
"Unexpected remote data type: "
+
remoteDataType
);
}
return
data
;
}
return
plainTextParser
(
data
,
this
.
options
.
lineSeparator
,
this
.
options
.
cellSeparator
);
};
/**
* Filter result
* @param {Object} result
* @param {String} filter
* @returns {boolean} Include this result
* @private
*/
$
.
Autocompleter
.
prototype
.
filterResult
=
function
(
result
,
filter
)
{
if
(
!
result
.
value
)
{
return
false
;
}
if
(
this
.
options
.
filterResults
)
{
var
pattern
=
this
.
matchStringConverter
(
filter
);
var
testValue
=
this
.
matchStringConverter
(
result
.
value
);
if
(
!
this
.
options
.
matchCase
)
{
pattern
=
pattern
.
toLowerCase
();
testValue
=
testValue
.
toLowerCase
();
}
var
patternIndex
=
testValue
.
indexOf
(
pattern
);
if
(
this
.
options
.
matchInside
)
{
return
patternIndex
>
-
1
;
}
else
{
return
patternIndex
===
0
;
}
}
return
true
;
};
/**
* Filter results
* @param results
* @param filter
*/
$
.
Autocompleter
.
prototype
.
filterResults
=
function
(
results
,
filter
)
{
var
filtered
=
[];
var
i
,
result
;
for
(
i
=
0
;
i
<
results
.
length
;
i
++
)
{
result
=
sanitizeResult
(
results
[
i
]);
if
(
this
.
filterResult
(
result
,
filter
))
{
filtered
.
push
(
result
);
}
}
if
(
this
.
options
.
sortResults
)
{
filtered
=
this
.
sortResults
(
filtered
,
filter
);
}
if
(
this
.
options
.
maxItemsToShow
>
0
&&
this
.
options
.
maxItemsToShow
<
filtered
.
length
)
{
filtered
.
length
=
this
.
options
.
maxItemsToShow
;
}
return
filtered
;
};
/**
* Sort results
* @param results
* @param filter
*/
$
.
Autocompleter
.
prototype
.
sortResults
=
function
(
results
,
filter
)
{
var
self
=
this
;
var
sortFunction
=
this
.
options
.
sortFunction
;
if
(
!
$
.
isFunction
(
sortFunction
))
{
sortFunction
=
function
(
a
,
b
,
f
)
{
return
sortValueAlpha
(
a
,
b
,
self
.
options
.
matchCase
);
};
}
results
.
sort
(
function
(
a
,
b
)
{
return
sortFunction
(
a
,
b
,
filter
,
self
.
options
);
});
return
results
;
};
/**
* Convert string before matching
* @param s
* @param a
* @param b
*/
$
.
Autocompleter
.
prototype
.
matchStringConverter
=
function
(
s
,
a
,
b
)
{
var
converter
=
this
.
options
.
matchStringConverter
;
if
(
$
.
isFunction
(
converter
))
{
s
=
converter
(
s
,
a
,
b
);
}
return
s
;
};
/**
* Convert string before use
* @param s
* @param a
* @param b
*/
$
.
Autocompleter
.
prototype
.
beforeUseConverter
=
function
(
s
,
a
,
b
)
{
s
=
this
.
getValue
();
var
converter
=
this
.
options
.
beforeUseConverter
;
if
(
$
.
isFunction
(
converter
))
{
s
=
converter
(
s
,
a
,
b
);
}
return
s
;
};
/**
* Enable finish on blur event
*/
$
.
Autocompleter
.
prototype
.
enableFinishOnBlur
=
function
()
{
this
.
finishOnBlur_
=
true
;
};
/**
* Disable finish on blur event
*/
$
.
Autocompleter
.
prototype
.
disableFinishOnBlur
=
function
()
{
this
.
finishOnBlur_
=
false
;
};
/**
* Create a results item (LI element) from a result
* @param result
*/
$
.
Autocompleter
.
prototype
.
createItemFromResult
=
function
(
result
)
{
var
self
=
this
;
var
$li
=
$
(
'<li>'
+
this
.
showResult
(
result
.
value
,
result
.
data
)
+
'</li>'
);
$li
.
data
({
value
:
result
.
value
,
data
:
result
.
data
})
.
click
(
function
()
{
self
.
selectItem
(
$li
);
})
.
mousedown
(
self
.
disableFinishOnBlur
)
.
mouseup
(
self
.
enableFinishOnBlur
)
;
return
$li
;
};
/**
* Get all items from the results list
* @param result
*/
$
.
Autocompleter
.
prototype
.
getItems
=
function
()
{
return
$
(
'>ul>li'
,
this
.
dom
.
$results
);
};
/**
* Show all results
* @param results
* @param filter
*/
$
.
Autocompleter
.
prototype
.
showResults
=
function
(
results
,
filter
)
{
var
numResults
=
results
.
length
;
var
self
=
this
;
var
$ul
=
$
(
'<ul></ul>'
);
var
i
,
result
,
$li
,
autoWidth
,
first
=
false
,
$first
=
false
;
if
(
numResults
)
{
for
(
i
=
0
;
i
<
numResults
;
i
++
)
{
result
=
results
[
i
];
$li
=
this
.
createItemFromResult
(
result
);
$ul
.
append
(
$li
);
if
(
first
===
false
)
{
first
=
String
(
result
.
value
);
$first
=
$li
;
$li
.
addClass
(
this
.
options
.
firstItemClass
);
}
if
(
i
===
numResults
-
1
)
{
$li
.
addClass
(
this
.
options
.
lastItemClass
);
}
}
// Always recalculate position before showing since window size or
// input element location may have changed.
this
.
position
();
this
.
dom
.
$results
.
html
(
$ul
).
show
();
if
(
this
.
options
.
autoWidth
)
{
autoWidth
=
this
.
dom
.
$elem
.
outerWidth
()
-
this
.
dom
.
$results
.
outerWidth
()
+
this
.
dom
.
$results
.
width
();
this
.
dom
.
$results
.
css
(
this
.
options
.
autoWidth
,
autoWidth
);
}
this
.
getItems
().
hover
(
function
()
{
self
.
focusItem
(
this
);
},
function
()
{
/* void */
}
);
if
(
this
.
autoFill
(
first
,
filter
)
||
this
.
options
.
selectFirst
||
(
this
.
options
.
selectOnly
&&
numResults
===
1
))
{
this
.
focusItem
(
$first
);
}
this
.
active_
=
true
;
}
else
{
this
.
hideResults
();
this
.
active_
=
false
;
}
};
$
.
Autocompleter
.
prototype
.
showResult
=
function
(
value
,
data
)
{
if
(
$
.
isFunction
(
this
.
options
.
showResult
))
{
return
this
.
options
.
showResult
(
value
,
data
);
}
else
{
return
value
;
}
};
$
.
Autocompleter
.
prototype
.
autoFill
=
function
(
value
,
filter
)
{
var
lcValue
,
lcFilter
,
valueLength
,
filterLength
;
if
(
this
.
options
.
autoFill
&&
this
.
lastKeyPressed_
!==
8
)
{
lcValue
=
String
(
value
).
toLowerCase
();
lcFilter
=
String
(
filter
).
toLowerCase
();
valueLength
=
value
.
length
;
filterLength
=
filter
.
length
;
if
(
lcValue
.
substr
(
0
,
filterLength
)
===
lcFilter
)
{
var
d
=
this
.
getDelimiterOffsets
();
var
pad
=
d
.
start
?
' '
:
''
;
// if there is a preceding delimiter
this
.
setValue
(
pad
+
value
);
var
start
=
filterLength
+
d
.
start
+
pad
.
length
;
var
end
=
valueLength
+
d
.
start
+
pad
.
length
;
this
.
selectRange
(
start
,
end
);
return
true
;
}
}
return
false
;
};
$
.
Autocompleter
.
prototype
.
focusNext
=
function
()
{
this
.
focusMove
(
+
1
);
};
$
.
Autocompleter
.
prototype
.
focusPrev
=
function
()
{
this
.
focusMove
(
-
1
);
};
$
.
Autocompleter
.
prototype
.
focusMove
=
function
(
modifier
)
{
var
$items
=
this
.
getItems
();
modifier
=
sanitizeInteger
(
modifier
,
0
);
if
(
modifier
)
{
for
(
var
i
=
0
;
i
<
$items
.
length
;
i
++
)
{
if
(
$
(
$items
[
i
]).
hasClass
(
this
.
selectClass_
))
{
this
.
focusItem
(
i
+
modifier
);
return
;
}
}
}
this
.
focusItem
(
0
);
};
$
.
Autocompleter
.
prototype
.
focusItem
=
function
(
item
)
{
var
$item
,
$items
=
this
.
getItems
();
if
(
$items
.
length
)
{
$items
.
removeClass
(
this
.
selectClass_
).
removeClass
(
this
.
options
.
selectClass
);
if
(
typeof
item
===
'number'
)
{
if
(
item
<
0
)
{
item
=
0
;
}
else
if
(
item
>=
$items
.
length
)
{
item
=
$items
.
length
-
1
;
}
$item
=
$
(
$items
[
item
]);
}
else
{
$item
=
$
(
item
);
}
if
(
$item
)
{
$item
.
addClass
(
this
.
selectClass_
).
addClass
(
this
.
options
.
selectClass
);
}
}
};
$
.
Autocompleter
.
prototype
.
selectCurrent
=
function
()
{
var
$item
=
$
(
'li.'
+
this
.
selectClass_
,
this
.
dom
.
$results
);
if
(
$item
.
length
===
1
)
{
this
.
selectItem
(
$item
);
}
else
{
this
.
deactivate
(
false
);
}
};
$
.
Autocompleter
.
prototype
.
selectItem
=
function
(
$li
)
{
var
value
=
$li
.
data
(
'value'
);
var
data
=
$li
.
data
(
'data'
);
var
displayValue
=
this
.
displayValue
(
value
,
data
);
var
processedDisplayValue
=
this
.
beforeUseConverter
(
displayValue
);
this
.
lastProcessedValue_
=
processedDisplayValue
;
this
.
lastSelectedValue_
=
processedDisplayValue
;
var
d
=
this
.
getDelimiterOffsets
();
var
delimiter
=
this
.
options
.
delimiterChar
;
var
elem
=
this
.
dom
.
$elem
;
var
extraCaretPos
=
0
;
if
(
this
.
options
.
useDelimiter
)
{
// if there is a preceding delimiter, add a space after the delimiter
if
(
elem
.
val
().
substring
(
d
.
start
-
1
,
d
.
start
)
==
delimiter
&&
delimiter
!=
' '
)
{
displayValue
=
' '
+
displayValue
;
}
// if there is not already a delimiter trailing this value, add it
if
(
elem
.
val
().
substring
(
d
.
end
,
d
.
end
+
1
)
!=
delimiter
&&
this
.
lastKeyPressed_
!=
this
.
options
.
delimiterKeyCode
)
{
displayValue
=
displayValue
+
delimiter
;
}
else
{
// move the cursor after the existing trailing delimiter
extraCaretPos
=
1
;
}
}
this
.
setValue
(
displayValue
);
this
.
setCaret
(
d
.
start
+
displayValue
.
length
+
extraCaretPos
);
this
.
callHook
(
'onItemSelect'
,
{
value
:
value
,
data
:
data
});
this
.
deactivate
(
true
);
elem
.
focus
();
};
$
.
Autocompleter
.
prototype
.
displayValue
=
function
(
value
,
data
)
{
if
(
$
.
isFunction
(
this
.
options
.
displayValue
))
{
return
this
.
options
.
displayValue
(
value
,
data
);
}
return
value
;
};
$
.
Autocompleter
.
prototype
.
hideResults
=
function
()
{
this
.
dom
.
$results
.
hide
();
};
$
.
Autocompleter
.
prototype
.
deactivate
=
function
(
finish
)
{
if
(
this
.
finishTimeout_
)
{
clearTimeout
(
this
.
finishTimeout_
);
}
if
(
this
.
keyTimeout_
)
{
clearTimeout
(
this
.
keyTimeout_
);
}
if
(
finish
)
{
if
(
this
.
lastProcessedValue_
!==
this
.
lastSelectedValue_
)
{
if
(
this
.
options
.
mustMatch
)
{
this
.
setValue
(
''
);
}
this
.
callHook
(
'onNoMatch'
);
}
if
(
this
.
active_
)
{
this
.
callHook
(
'onFinish'
);
}
this
.
lastKeyPressed_
=
null
;
this
.
lastProcessedValue_
=
null
;
this
.
lastSelectedValue_
=
null
;
this
.
active_
=
false
;
}
this
.
hideResults
();
};
$
.
Autocompleter
.
prototype
.
selectRange
=
function
(
start
,
end
)
{
var
input
=
this
.
dom
.
$elem
.
get
(
0
);
if
(
input
.
setSelectionRange
)
{
input
.
focus
();
input
.
setSelectionRange
(
start
,
end
);
}
else
if
(
input
.
createTextRange
)
{
var
range
=
input
.
createTextRange
();
range
.
collapse
(
true
);
range
.
moveEnd
(
'character'
,
end
);
range
.
moveStart
(
'character'
,
start
);
range
.
select
();
}
};
/**
* Move caret to position
* @param {Number} pos
*/
$
.
Autocompleter
.
prototype
.
setCaret
=
function
(
pos
)
{
this
.
selectRange
(
pos
,
pos
);
};
/**
* Get caret position
*/
$
.
Autocompleter
.
prototype
.
getCaret
=
function
()
{
var
elem
=
this
.
dom
.
$elem
;
if
(
$
.
browser
.
msie
)
{
// ie
var
selection
=
document
.
selection
;
if
(
elem
[
0
].
tagName
.
toLowerCase
()
!=
'textarea'
)
{
var
val
=
elem
.
val
();
var
range
=
selection
.
createRange
().
duplicate
();
range
.
moveEnd
(
'character'
,
val
.
length
);
var
s
=
(
range
.
text
==
''
?
val
.
length
:
val
.
lastIndexOf
(
range
.
text
)
);
range
=
selection
.
createRange
().
duplicate
();
range
.
moveStart
(
'character'
,
-
val
.
length
);
var
e
=
range
.
text
.
length
;
}
else
{
var
range
=
selection
.
createRange
();
var
stored_range
=
range
.
duplicate
();
stored_range
.
moveToElementText
(
elem
[
0
]);
stored_range
.
setEndPoint
(
'EndToEnd'
,
range
);
var
s
=
stored_range
.
text
.
length
-
range
.
text
.
length
;
var
e
=
s
+
range
.
text
.
length
;
}
}
else
{
// ff, chrome, safari
var
s
=
elem
[
0
].
selectionStart
;
var
e
=
elem
[
0
].
selectionEnd
;
}
return
{
start
:
s
,
end
:
e
};
};
/**
* Set the value that is currently being autocompleted
* @param {String} value
*/
$
.
Autocompleter
.
prototype
.
setValue
=
function
(
value
)
{
if
(
this
.
options
.
useDelimiter
)
{
// set the substring between the current delimiters
var
val
=
this
.
dom
.
$elem
.
val
();
var
d
=
this
.
getDelimiterOffsets
();
var
preVal
=
val
.
substring
(
0
,
d
.
start
);
var
postVal
=
val
.
substring
(
d
.
end
);
value
=
preVal
+
value
+
postVal
;
}
this
.
dom
.
$elem
.
val
(
value
);
};
/**
* Get the value currently being autocompleted
* @param {String} value
*/
$
.
Autocompleter
.
prototype
.
getValue
=
function
()
{
var
val
=
this
.
dom
.
$elem
.
val
();
if
(
this
.
options
.
useDelimiter
)
{
var
d
=
this
.
getDelimiterOffsets
();
return
val
.
substring
(
d
.
start
,
d
.
end
).
trim
();
}
else
{
return
val
;
}
};
/**
* Get the offsets of the value currently being autocompleted
*/
$
.
Autocompleter
.
prototype
.
getDelimiterOffsets
=
function
()
{
var
val
=
this
.
dom
.
$elem
.
val
();
if
(
this
.
options
.
useDelimiter
)
{
var
preCaretVal
=
val
.
substring
(
0
,
this
.
getCaret
().
start
);
var
start
=
preCaretVal
.
lastIndexOf
(
this
.
options
.
delimiterChar
)
+
1
;
var
postCaretVal
=
val
.
substring
(
this
.
getCaret
().
start
);
var
end
=
postCaretVal
.
indexOf
(
this
.
options
.
delimiterChar
);
if
(
end
==
-
1
)
end
=
val
.
length
;
end
+=
this
.
getCaret
().
start
;
}
else
{
start
=
0
;
end
=
val
.
length
;
}
return
{
start
:
start
,
end
:
end
};
};
})(
jQuery
);
lms/static/css/vendor/jquery.autocomplete.css
0 → 100644
View file @
41f1e9d3
.acInput
{
width
:
200px
;
}
.acResults
{
padding
:
0px
;
border
:
1px
solid
WindowFrame
;
background-color
:
Window
;
overflow
:
hidden
;
}
.acResults
ul
{
margin
:
0px
;
padding
:
0px
;
list-style-position
:
outside
;
list-style
:
none
;
}
.acResults
ul
li
{
margin
:
0px
;
padding
:
2px
5px
;
cursor
:
pointer
;
display
:
block
;
font
:
menu
;
font-size
:
12px
;
overflow
:
hidden
;
}
.acLoading
{
background
:
url('indicator.gif')
right
center
no-repeat
;
}
.acSelect
{
background-color
:
Highlight
;
color
:
HighlightText
;
}
lms/static/sass/_discussion.scss
View file @
41f1e9d3
...
...
@@ -124,23 +124,30 @@ $discussion_input_width: 60%;
font-weight
:
bold
;
display
:
block
;
}
.thread-body
{
.thread-body
,
.content-body
{
@include
discussion-font
;
font-size
:
$comment_body_size
;
margin-top
:
7px
;
margin-bottom
:
2px
;
p
{
@include
discussion-font
;
margin
:
0
;
}
}
.thread-tags
{
.thread-tag
{
@include
discussion-font
;
border-right
:
3px
solid
#205C85
;
padding-right
:
5px
;
font-size
:
0
.75em
;
border-width
:
0px
1px
1px
0px
;
border-style
:
solid
;
border-color
:
#205C85
;
padding
:
0px
3px
3px
0px
;
margin-right
:
5px
;
border-radius
:
15
px
;
border-radius
:
4
px
;
color
:
#205C85
;
&
:hover
{
color
:
#3CC5E7
;
border-
right
:
3px
solid
#3CC5E7
;
border-
color
:
#3CC5E7
;
}
}
}
...
...
@@ -188,7 +195,7 @@ $discussion_input_width: 60%;
margin-left
:
$comment_margin_left
;
overflow
:
hidden
;
.comment
{
.comment-body
{
.comment-body
,
.content-body
{
@include
discussion-font
;
font-size
:
$comment_body_size
;
margin-top
:
3px
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment