2018-11-21 19:01:54 +00:00
var packages = {
available : { providers : { } , pkgs : { } } ,
installed : { providers : { } , pkgs : { } }
} ;
var currentDisplayMode = 'available' , currentDisplayRows = [ ] ;
function parseList ( s , dest )
{
var re = /([^\n]*)\n/g ,
pkg = null , key = null , val = null , m ;
while ( ( m = re . exec ( s ) ) !== null ) {
if ( m [ 1 ] . match ( /^\s(.*)$/ ) ) {
if ( pkg !== null && key !== null && val !== null )
val += '\n' + RegExp . $1 . trim ( ) ;
continue ;
}
if ( key !== null && val !== null ) {
switch ( key ) {
case 'package' :
pkg = { name : val } ;
break ;
case 'depends' :
case 'provides' :
var list = val . split ( /\s*,\s*/ ) ;
if ( list . length !== 1 || list [ 0 ] . length > 0 )
pkg [ key ] = list ;
break ;
case 'installed-time' :
pkg . installtime = new Date ( + val * 1000 ) ;
break ;
case 'installed-size' :
pkg . installsize = + val ;
break ;
case 'status' :
var stat = val . split ( /\s+/ ) ,
mode = stat [ 1 ] ,
installed = stat [ 2 ] ;
switch ( mode ) {
case 'user' :
case 'hold' :
pkg [ mode ] = true ;
break ;
}
switch ( installed ) {
case 'installed' :
pkg . installed = true ;
break ;
}
break ;
case 'essential' :
if ( val === 'yes' )
pkg . essential = true ;
break ;
case 'size' :
pkg . size = + val ;
break ;
case 'architecture' :
case 'auto-installed' :
case 'filename' :
case 'sha256sum' :
case 'section' :
break ;
default :
pkg [ key ] = val ;
break ;
}
key = val = null ;
}
if ( m [ 1 ] . trim ( ) . match ( /^([\w-]+)\s*:(.+)$/ ) ) {
key = RegExp . $1 . toLowerCase ( ) ;
val = RegExp . $2 . trim ( ) ;
}
else {
dest . pkgs [ pkg . name ] = pkg ;
var provides = dest . providers [ pkg . name ] ? [ ] : [ pkg . name ] ;
if ( pkg . provides )
provides . push . apply ( provides , pkg . provides ) ;
provides . forEach ( function ( p ) {
dest . providers [ p ] = dest . providers [ p ] || [ ] ;
dest . providers [ p ] . push ( pkg ) ;
} ) ;
}
}
}
function display ( pattern )
{
var src = packages [ currentDisplayMode === 'updates' ? 'installed' : currentDisplayMode ] ,
table = document . querySelector ( '#packages' ) ,
pager = document . querySelector ( '#pager' ) ;
currentDisplayRows . length = 0 ;
if ( typeof ( pattern ) === 'string' && pattern . length > 0 )
pattern = new RegExp ( pattern . replace ( /[.*+?^${}()|[\]\\]/g , '\\$&' ) , 'ig' ) ;
for ( var name in src . pkgs ) {
var pkg = src . pkgs [ name ] ,
desc = pkg . description || '' ,
altsize = null ;
if ( ! pkg . size && packages . available . pkgs [ name ] )
altsize = packages . available . pkgs [ name ] . size ;
if ( ! desc && packages . available . pkgs [ name ] )
desc = packages . available . pkgs [ name ] . description || '' ;
desc = desc . split ( /\n/ ) ;
desc = desc [ 0 ] . trim ( ) + ( desc . length > 1 ? '…' : '' ) ;
if ( ( pattern instanceof RegExp ) &&
! name . match ( pattern ) && ! desc . match ( pattern ) )
continue ;
var btn , ver ;
if ( currentDisplayMode === 'updates' ) {
2019-06-19 09:21:18 +00:00
var avail = packages . available . pkgs [ name ] ,
inst = packages . installed . pkgs [ name ] ;
if ( ! inst || ! inst . installed )
continue ;
2019-01-04 08:15:49 +00:00
if ( ! avail || compareVersion ( avail . version , pkg . version ) <= 0 )
2018-11-21 19:01:54 +00:00
continue ;
ver = '%s » %s' . format (
truncateVersion ( pkg . version || '-' ) ,
truncateVersion ( avail . version || '-' ) ) ;
btn = E ( 'div' , {
'class' : 'btn cbi-button-positive' ,
'data-package' : name ,
'click' : handleInstall
} , _ ( 'Upgrade…' ) ) ;
}
else if ( currentDisplayMode === 'installed' ) {
2019-06-19 09:21:18 +00:00
if ( ! pkg . installed )
continue ;
2018-11-21 19:01:54 +00:00
ver = truncateVersion ( pkg . version || '-' ) ;
btn = E ( 'div' , {
'class' : 'btn cbi-button-negative' ,
'data-package' : name ,
'click' : handleRemove
2019-06-25 19:28:44 +00:00
} , _ ( 'Remove…' ) ) ;
2018-11-21 19:01:54 +00:00
}
else {
2019-06-19 09:21:18 +00:00
var inst = packages . installed . pkgs [ name ] ;
2018-11-21 19:01:54 +00:00
ver = truncateVersion ( pkg . version || '-' ) ;
2019-06-19 09:21:18 +00:00
if ( ! inst || ! inst . installed )
2018-11-21 19:01:54 +00:00
btn = E ( 'div' , {
'class' : 'btn cbi-button-action' ,
'data-package' : name ,
'click' : handleInstall
} , _ ( 'Install…' ) ) ;
2019-06-19 09:21:18 +00:00
else if ( inst . installed && inst . version != pkg . version )
2018-11-21 19:01:54 +00:00
btn = E ( 'div' , {
'class' : 'btn cbi-button-positive' ,
'data-package' : name ,
'click' : handleInstall
} , _ ( 'Upgrade…' ) ) ;
else
btn = E ( 'div' , {
'class' : 'btn cbi-button-neutral' ,
'disabled' : 'disabled'
} , _ ( 'Installed' ) ) ;
}
name = '%h' . format ( name ) ;
desc = '%h' . format ( desc || '-' ) ;
if ( pattern ) {
name = name . replace ( pattern , '<ins>$&</ins>' ) ;
desc = desc . replace ( pattern , '<ins>$&</ins>' ) ;
}
currentDisplayRows . push ( [
name ,
ver ,
pkg . size ? '%.1024mB' . format ( pkg . size )
: ( altsize ? '~%.1024mB' . format ( altsize ) : '-' ) ,
desc ,
btn
] ) ;
}
currentDisplayRows . sort ( function ( a , b ) {
if ( a [ 0 ] < b [ 0 ] )
return - 1 ;
else if ( a [ 0 ] > b [ 0 ] )
return 1 ;
else
return 0 ;
} ) ;
pager . parentNode . style . display = '' ;
pager . setAttribute ( 'data-offset' , 100 ) ;
handlePage ( { target : pager . querySelector ( '.prev' ) } ) ;
}
function handlePage ( ev )
{
var filter = document . querySelector ( 'input[name="filter"]' ) ,
pager = ev . target . parentNode ,
offset = + pager . getAttribute ( 'data-offset' ) ,
next = ev . target . classList . contains ( 'next' ) ;
if ( ( next && ( offset + 100 ) >= currentDisplayRows . length ) ||
( ! next && ( offset < 100 ) ) )
return ;
offset += next ? 100 : - 100 ;
pager . setAttribute ( 'data-offset' , offset ) ;
pager . querySelector ( '.text' ) . firstChild . data = currentDisplayRows . length
? _ ( 'Displaying %d-%d of %d' ) . format ( 1 + offset , Math . min ( offset + 100 , currentDisplayRows . length ) , currentDisplayRows . length )
: _ ( 'No packages' ) ;
if ( offset < 100 )
pager . querySelector ( '.prev' ) . setAttribute ( 'disabled' , 'disabled' ) ;
else
pager . querySelector ( '.prev' ) . removeAttribute ( 'disabled' ) ;
if ( ( offset + 100 ) >= currentDisplayRows . length )
pager . querySelector ( '.next' ) . setAttribute ( 'disabled' , 'disabled' ) ;
else
pager . querySelector ( '.next' ) . removeAttribute ( 'disabled' ) ;
var placeholder = _ ( 'No information available' ) ;
if ( filter . value )
placeholder = [
E ( 'span' , { } , _ ( 'No packages matching "<strong>%h</strong>".' ) . format ( filter . value ) ) , ' (' ,
E ( 'a' , { href : '#' , onclick : 'handleReset(event)' } , _ ( 'Reset' ) ) , ')'
] ;
cbi _update _table ( '#packages' , currentDisplayRows . slice ( offset , offset + 100 ) ,
placeholder ) ;
}
function handleMode ( ev )
{
var tab = findParent ( ev . target , 'li' ) ;
if ( tab . getAttribute ( 'data-mode' ) === currentDisplayMode )
return ;
tab . parentNode . querySelectorAll ( 'li' ) . forEach ( function ( li ) {
li . classList . remove ( 'cbi-tab' ) ;
li . classList . add ( 'cbi-tab-disabled' ) ;
} ) ;
tab . classList . remove ( 'cbi-tab-disabled' ) ;
tab . classList . add ( 'cbi-tab' ) ;
currentDisplayMode = tab . getAttribute ( 'data-mode' ) ;
display ( document . querySelector ( 'input[name="filter"]' ) . value ) ;
ev . target . blur ( ) ;
ev . preventDefault ( ) ;
}
function orderOf ( c )
{
if ( c === '~' )
return - 1 ;
else if ( c === '' || c >= '0' && c <= '9' )
return 0 ;
else if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) )
return c . charCodeAt ( 0 ) ;
else
return c . charCodeAt ( 0 ) + 256 ;
}
function compareVersion ( val , ref )
{
var vi = 0 , ri = 0 ,
isdigit = { 0 : 1 , 1 : 1 , 2 : 1 , 3 : 1 , 4 : 1 , 5 : 1 , 6 : 1 , 7 : 1 , 8 : 1 , 9 : 1 } ;
val = val || '' ;
ref = ref || '' ;
2019-01-04 08:15:49 +00:00
if ( val === ref )
return 0 ;
2018-11-21 19:01:54 +00:00
while ( vi < val . length || ri < ref . length ) {
var first _diff = 0 ;
while ( ( vi < val . length && ! isdigit [ val . charAt ( vi ) ] ) ||
( ri < ref . length && ! isdigit [ ref . charAt ( ri ) ] ) ) {
var vc = orderOf ( val . charAt ( vi ) ) , rc = orderOf ( ref . charAt ( ri ) ) ;
if ( vc !== rc )
return vc - rc ;
vi ++ ; ri ++ ;
}
while ( val . charAt ( vi ) === '0' )
vi ++ ;
while ( ref . charAt ( ri ) === '0' )
ri ++ ;
while ( isdigit [ val . charAt ( vi ) ] && isdigit [ ref . charAt ( ri ) ] ) {
first _diff = first _diff || ( val . charCodeAt ( vi ) - ref . charCodeAt ( ri ) ) ;
vi ++ ; ri ++ ;
}
if ( isdigit [ val . charAt ( vi ) ] )
return 1 ;
else if ( isdigit [ ref . charAt ( ri ) ] )
return - 1 ;
else if ( first _diff )
return first _diff ;
}
return 0 ;
}
function versionSatisfied ( ver , ref , vop )
{
var r = compareVersion ( ver , ref ) ;
switch ( vop ) {
case '<' :
case '<=' :
return r <= 0 ;
case '>' :
case '>=' :
return r >= 0 ;
case '<<' :
return r < 0 ;
case '>>' :
return r > 0 ;
case '=' :
return r == 0 ;
}
return false ;
}
function pkgStatus ( pkg , vop , ver , info )
{
info . errors = info . errors || [ ] ;
info . install = info . install || [ ] ;
if ( pkg . installed ) {
if ( vop && ! versionSatisfied ( pkg . version , ver , vop ) ) {
var repl = null ;
( packages . available . providers [ pkg . name ] || [ ] ) . forEach ( function ( p ) {
if ( ! repl && versionSatisfied ( p . version , ver , vop ) )
repl = p ;
} ) ;
if ( repl ) {
info . install . push ( repl ) ;
return E ( 'span' , {
'class' : 'label' ,
'data-tooltip' : _ ( 'Requires update to %h %h' )
. format ( repl . name , repl . version )
} , _ ( 'Needs upgrade' ) ) ;
}
info . errors . push ( _ ( 'The installed version of package <em>%h</em> is not compatible, require %s while %s is installed.' ) . format ( pkg . name , truncateVersion ( ver , vop ) , truncateVersion ( pkg . version ) ) ) ;
return E ( 'span' , {
'class' : 'label warning' ,
'data-tooltip' : _ ( 'Require version %h %h,\ninstalled %h' )
. format ( vop , ver , pkg . version )
} , _ ( 'Version incompatible' ) ) ;
}
return E ( 'span' , { 'class' : 'label notice' } , _ ( 'Installed' ) ) ;
}
else if ( ! pkg . missing ) {
if ( ! vop || versionSatisfied ( pkg . version , ver , vop ) ) {
info . install . push ( pkg ) ;
return E ( 'span' , { 'class' : 'label' } , _ ( 'Not installed' ) ) ;
}
info . errors . push ( _ ( 'The repository version of package <em>%h</em> is not compatible, require %s but only %s is available.' )
. format ( pkg . name , truncateVersion ( ver , vop ) , truncateVersion ( pkg . version ) ) ) ;
return E ( 'span' , {
'class' : 'label warning' ,
'data-tooltip' : _ ( 'Require version %h %h,\ninstalled %h' )
. format ( vop , ver , pkg . version )
} , _ ( 'Version incompatible' ) ) ;
}
else {
info . errors . push ( _ ( 'Required dependency package <em>%h</em> is not available in any repository.' ) . format ( pkg . name ) ) ;
return E ( 'span' , { 'class' : 'label warning' } , _ ( 'Not available' ) ) ;
}
}
function renderDependencyItem ( dep , info )
{
var li = E ( 'li' ) ,
vop = dep . version ? dep . version [ 0 ] : null ,
ver = dep . version ? dep . version [ 1 ] : null ,
depends = [ ] ;
for ( var i = 0 ; dep . pkgs && i < dep . pkgs . length ; i ++ ) {
var pkg = packages . installed . pkgs [ dep . pkgs [ i ] ] ||
packages . available . pkgs [ dep . pkgs [ i ] ] ||
{ name : dep . name } ;
if ( i > 0 )
li . appendChild ( document . createTextNode ( ' | ' ) ) ;
var text = pkg . name ;
if ( pkg . installsize )
text += ' (%.1024mB)' . format ( pkg . installsize ) ;
else if ( pkg . size )
text += ' (~%.1024mB)' . format ( pkg . size ) ;
li . appendChild ( E ( 'span' , { 'data-tooltip' : pkg . description } ,
[ text , ' ' , pkgStatus ( pkg , vop , ver , info ) ] ) ) ;
( pkg . depends || [ ] ) . forEach ( function ( d ) {
if ( depends . indexOf ( d ) === - 1 )
depends . push ( d ) ;
} ) ;
}
if ( ! li . firstChild )
li . appendChild ( E ( 'span' , { } ,
[ dep . name , ' ' ,
pkgStatus ( { name : dep . name , missing : true } , vop , ver , info ) ] ) ) ;
var subdeps = renderDependencies ( depends , info ) ;
if ( subdeps )
li . appendChild ( subdeps ) ;
return li ;
}
function renderDependencies ( depends , info )
{
var deps = depends || [ ] ,
items = [ ] ;
info . seen = info . seen || [ ] ;
for ( var i = 0 ; i < deps . length ; i ++ ) {
if ( deps [ i ] === 'libc' )
continue ;
if ( deps [ i ] . match ( /^(.+)\s+\((<=|<|>|>=|=|<<|>>)(.+)\)$/ ) ) {
dep = RegExp . $1 . trim ( ) ;
vop = RegExp . $2 . trim ( ) ;
ver = RegExp . $3 . trim ( ) ;
}
else {
dep = deps [ i ] . trim ( ) ;
vop = ver = null ;
}
if ( info . seen [ dep ] )
continue ;
var pkgs = [ ] ;
( packages . installed . providers [ dep ] || [ ] ) . forEach ( function ( p ) {
if ( pkgs . indexOf ( p . name ) === - 1 ) pkgs . push ( p . name ) ;
} ) ;
( packages . available . providers [ dep ] || [ ] ) . forEach ( function ( p ) {
if ( pkgs . indexOf ( p . name ) === - 1 ) pkgs . push ( p . name ) ;
} ) ;
info . seen [ dep ] = {
name : dep ,
pkgs : pkgs ,
version : [ vop , ver ]
} ;
items . push ( renderDependencyItem ( info . seen [ dep ] , info ) ) ;
}
if ( items . length )
return E ( 'ul' , { 'class' : 'deps' } , items ) ;
return null ;
}
function truncateVersion ( v , op )
{
v = v . replace ( /\b(([a-f0-9]{8})[a-f0-9]{24,32})\b/ ,
'<span data-tooltip="$1">$2…</span>' ) ;
if ( ! op || op === '=' )
return v ;
return '%h %h' . format ( op , v ) ;
}
function handleReset ( ev )
{
var filter = document . querySelector ( 'input[name="filter"]' ) ;
filter . value = '' ;
display ( ) ;
}
function handleInstall ( ev )
{
var name = ev . target . getAttribute ( 'data-package' ) ,
pkg = packages . available . pkgs [ name ] ,
depcache = { } ,
size ;
if ( pkg . installsize )
size = _ ( '~%.1024mB installed' ) . format ( pkg . installsize ) ;
else if ( pkg . size )
size = _ ( '~%.1024mB compressed' ) . format ( pkg . size ) ;
else
size = _ ( 'unknown' ) ;
var deps = renderDependencies ( pkg . depends , depcache ) ,
tree = null , errs = null , inst = null , desc = null ;
if ( depcache . errors && depcache . errors . length ) {
errs = E ( 'ul' , { 'class' : 'errors' } ) ;
depcache . errors . forEach ( function ( err ) {
errs . appendChild ( E ( 'li' , { } , err ) ) ;
} ) ;
}
var totalsize = pkg . installsize || pkg . size || 0 ,
totalpkgs = 1 ;
if ( depcache . install && depcache . install . length )
depcache . install . forEach ( function ( ipkg ) {
totalsize += ipkg . installsize || ipkg . size || 0 ;
totalpkgs ++ ;
} ) ;
inst = E ( 'p' , { } ,
_ ( 'Require approx. %.1024mB size for %d package(s) to install.' )
. format ( totalsize , totalpkgs ) ) ;
if ( deps ) {
tree = E ( 'li' , '<strong>%s:</strong>' . format ( _ ( 'Dependencies' ) ) ) ;
tree . appendChild ( deps ) ;
}
if ( pkg . description ) {
desc = E ( 'div' , { } , [
E ( 'h5' , { } , _ ( 'Description' ) ) ,
E ( 'p' , { } , pkg . description )
] ) ;
}
L . showModal ( _ ( 'Details for package <em>%h</em>' ) . format ( pkg . name ) , [
E ( 'ul' , { } , [
E ( 'li' , '<strong>%s:</strong> %h' . format ( _ ( 'Version' ) , pkg . version ) ) ,
E ( 'li' , '<strong>%s:</strong> %h' . format ( _ ( 'Size' ) , size ) ) ,
tree || '' ,
] ) ,
desc || '' ,
errs || inst || '' ,
E ( 'div' , { 'class' : 'right' } , [
2019-06-19 11:29:19 +00:00
E ( 'label' , { 'class' : 'cbi-checkbox' , 'style' : 'float:left; padding-top:.5em' } , [
E ( 'input' , { 'type' : 'checkbox' , 'name' : 'overwrite' } ) , ' ' ,
_ ( 'Overwrite files from other package(s)' )
] ) ,
2018-11-21 19:01:54 +00:00
E ( 'div' , {
'class' : 'btn' ,
'click' : L . hideModal
} , _ ( 'Cancel' ) ) ,
' ' ,
E ( 'div' , {
'data-command' : 'install' ,
'data-package' : name ,
'class' : 'btn cbi-button-action' ,
'click' : handleOpkg
} , _ ( 'Install' ) )
] )
] ) ;
}
function handleManualInstall ( ev )
{
var name _or _url = document . querySelector ( 'input[name="install"]' ) . value ,
install = E ( 'div' , {
'class' : 'btn cbi-button-action' ,
'data-command' : 'install' ,
'data-package' : name _or _url ,
'click' : function ( ev ) {
document . querySelector ( 'input[name="install"]' ) . value = '' ;
handleOpkg ( ev ) ;
}
} , _ ( 'Install' ) ) , warning ;
if ( ! name _or _url . length ) {
return ;
}
else if ( name _or _url . indexOf ( '/' ) !== - 1 ) {
warning = E ( 'p' , { } , _ ( 'Installing packages from untrusted sources is a potential security risk! Really attempt to install <em>%h</em>?' ) . format ( name _or _url ) ) ;
}
else if ( ! packages . available . providers [ name _or _url ] ) {
warning = E ( 'p' , { } , _ ( 'The package <em>%h</em> is not available in any configured repository.' ) . format ( name _or _url ) ) ;
install = '' ;
}
else {
warning = E ( 'p' , { } , _ ( 'Really attempt to install <em>%h</em>?' ) . format ( name _or _url ) ) ;
}
L . showModal ( _ ( 'Manually install package' ) , [
warning ,
E ( 'div' , { 'class' : 'right' } , [
E ( 'div' , {
'click' : L . hideModal ,
'class' : 'btn cbi-button-neutral'
} , _ ( 'Cancel' ) ) ,
' ' , install
] )
] ) ;
}
function handleConfig ( ev )
{
L . showModal ( _ ( 'OPKG Configuration' ) , [
E ( 'p' , { 'class' : 'spinning' } , _ ( 'Loading configuration data…' ) )
] ) ;
L . get ( 'admin/system/opkg/config' , null , function ( xhr , conf ) {
var body = [
E ( 'p' , { } , _ ( 'Below is a listing of the various configuration files used by <em>opkg</em>. Use <em>opkg.conf</em> for global settings and <em>customfeeds.conf</em> for custom repository entries. The configuration in the other files may be changed but is usually not preserved by <em>sysupgrade</em>.' ) )
] ;
Object . keys ( conf ) . sort ( ) . forEach ( function ( file ) {
body . push ( E ( 'h5' , { } , '%h' . format ( file ) ) ) ;
body . push ( E ( 'textarea' , {
'name' : file ,
'rows' : Math . max ( Math . min ( conf [ file ] . match ( /\n/g ) . length , 10 ) , 3 )
} , '%h' . format ( conf [ file ] ) ) ) ;
} ) ;
body . push ( E ( 'div' , { 'class' : 'right' } , [
E ( 'div' , {
'class' : 'btn cbi-button-neutral' ,
'click' : L . hideModal
} , _ ( 'Cancel' ) ) ,
' ' ,
E ( 'div' , {
'class' : 'btn cbi-button-positive' ,
'click' : function ( ev ) {
var data = { } ;
findParent ( ev . target , '.modal' ) . querySelectorAll ( 'textarea[name]' )
. forEach ( function ( textarea ) {
data [ textarea . getAttribute ( 'name' ) ] = textarea . value
} ) ;
L . showModal ( _ ( 'OPKG Configuration' ) , [
E ( 'p' , { 'class' : 'spinning' } , _ ( 'Saving configuration data…' ) )
] ) ;
L . post ( 'admin/system/opkg/config' , { data : JSON . stringify ( data ) } , L . hideModal ) ;
}
} , _ ( 'Save' ) ) ,
] ) ) ;
L . showModal ( _ ( 'OPKG Configuration' ) , body ) ;
} ) ;
}
function handleRemove ( ev )
{
var name = ev . target . getAttribute ( 'data-package' ) ,
pkg = packages . installed . pkgs [ name ] ,
avail = packages . available . pkgs [ name ] || { } ,
size , desc ;
if ( avail . installsize )
size = _ ( '~%.1024mB installed' ) . format ( avail . installsize ) ;
else if ( avail . size )
size = _ ( '~%.1024mB compressed' ) . format ( avail . size ) ;
else
size = _ ( 'unknown' ) ;
if ( avail . description ) {
desc = E ( 'div' , { } , [
E ( 'h5' , { } , _ ( 'Description' ) ) ,
E ( 'p' , { } , avail . description )
] ) ;
}
L . showModal ( _ ( 'Remove package <em>%h</em>' ) . format ( pkg . name ) , [
E ( 'ul' , { } , [
E ( 'li' , '<strong>%s:</strong> %h' . format ( _ ( 'Version' ) , pkg . version ) ) ,
E ( 'li' , '<strong>%s:</strong> %h' . format ( _ ( 'Size' ) , size ) )
] ) ,
desc || '' ,
E ( 'div' , { 'style' : 'display:flex; justify-content:space-between; flex-wrap:wrap' } , [
E ( 'label' , { } , [
E ( 'input' , { type : 'checkbox' , checked : 'checked' , name : 'autoremove' } ) ,
_ ( 'Automatically remove unused dependencies' )
] ) ,
E ( 'div' , { 'style' : 'flex-grow:1' , 'class' : 'right' } , [
E ( 'div' , {
'class' : 'btn' ,
'click' : L . hideModal
} , _ ( 'Cancel' ) ) ,
' ' ,
E ( 'div' , {
'data-command' : 'remove' ,
'data-package' : name ,
'class' : 'btn cbi-button-negative' ,
'click' : handleOpkg
2019-06-25 19:28:44 +00:00
} , _ ( 'Remove' ) )
2018-11-21 19:01:54 +00:00
] )
] )
] ) ;
}
function handleOpkg ( ev )
{
var cmd = ev . target . getAttribute ( 'data-command' ) ,
pkg = ev . target . getAttribute ( 'data-package' ) ,
rem = document . querySelector ( 'input[name="autoremove"]' ) ,
2019-06-19 11:29:19 +00:00
owr = document . querySelector ( 'input[name="overwrite"]' ) ,
2018-11-21 19:01:54 +00:00
url = 'admin/system/opkg/exec/' + encodeURIComponent ( cmd ) ;
var dlg = L . showModal ( _ ( 'Executing package manager' ) , [
E ( 'p' , { 'class' : 'spinning' } ,
_ ( 'Waiting for the <em>opkg %h</em> command to complete…' ) . format ( cmd ) )
] ) ;
2019-06-19 11:29:19 +00:00
L . post ( url , { package : pkg , autoremove : rem ? rem . checked : false , overwrite : owr ? owr . checked : false } , function ( xhr , res ) {
2018-11-21 19:01:54 +00:00
dlg . removeChild ( dlg . lastChild ) ;
if ( res . stdout )
dlg . appendChild ( E ( 'pre' , [ res . stdout ] ) ) ;
if ( res . stderr ) {
dlg . appendChild ( E ( 'h5' , _ ( 'Errors' ) ) ) ;
dlg . appendChild ( E ( 'pre' , { 'class' : 'errors' } , [ res . stderr ] ) ) ;
}
if ( res . code !== 0 )
dlg . appendChild ( E ( 'p' , _ ( 'The <em>opkg %h</em> command failed with code <code>%d</code>.' ) . format ( cmd , ( res . code & 0xff ) || - 1 ) ) ) ;
dlg . appendChild ( E ( 'div' , { 'class' : 'right' } ,
E ( 'div' , {
'class' : 'btn' ,
'click' : function ( ) {
L . hideModal ( ) ;
updateLists ( ) ;
}
} , _ ( 'Dismiss' ) ) ) ) ;
} ) ;
}
function updateLists ( )
{
cbi _update _table ( '#packages' , [ ] ,
E ( 'div' , { 'class' : 'spinning' } , _ ( 'Loading package information…' ) ) ) ;
packages . available = { providers : { } , pkgs : { } } ;
packages . installed = { providers : { } , pkgs : { } } ;
L . get ( 'admin/system/opkg/statvfs' , null , function ( xhr , stat ) {
var pg = document . querySelector ( '.cbi-progressbar' ) ,
total = stat . blocks || 0 ,
free = stat . bfree || 0 ;
pg . firstElementChild . style . width = Math . floor ( total ? ( ( 100 / total ) * free ) : 100 ) + '%' ;
pg . setAttribute ( 'title' , '%s (%.1024mB)' . format ( pg . firstElementChild . style . width , free * ( stat . frsize || 0 ) ) ) ;
L . get ( 'admin/system/opkg/list/available' , null , function ( xhr ) {
parseList ( xhr . responseText , packages . available ) ;
L . get ( 'admin/system/opkg/list/installed' , null , function ( xhr ) {
parseList ( xhr . responseText , packages . installed ) ;
display ( document . querySelector ( 'input[name="filter"]' ) . value ) ;
} ) ;
} ) ;
} ) ;
}
window . requestAnimationFrame ( function ( ) {
var filter = document . querySelector ( 'input[name="filter"]' ) ,
keyTimeout = null ;
2018-11-22 07:57:09 +00:00
filter . value = filter . getAttribute ( 'value' ) ;
2018-11-21 19:01:54 +00:00
filter . addEventListener ( 'keyup' ,
function ( ev ) {
if ( keyTimeout !== null )
window . clearTimeout ( keyTimeout ) ;
keyTimeout = window . setTimeout ( function ( ) {
display ( ev . target . value ) ;
} , 250 ) ;
} ) ;
document . querySelector ( '#pager > .prev' ) . addEventListener ( 'click' , handlePage ) ;
document . querySelector ( '#pager > .next' ) . addEventListener ( 'click' , handlePage ) ;
document . querySelector ( '.cbi-tabmenu.mode' ) . addEventListener ( 'click' , handleMode ) ;
updateLists ( ) ;
} ) ;