Add files via upload

master
zmv7 2020-11-02 09:08:31 +05:00 committed by GitHub
parent e19debbced
commit ae0c6b3e1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 6006 additions and 0 deletions

160
mag/debug.html Normal file
View File

@ -0,0 +1,160 @@
<!doctype html>
<html>
<head>
<title>Debug entry point</title>
<meta charset='utf-8'>
<link rel="shortcut icon" href="system/settings/img/576/ico_settings_blue.png"/>
<!--<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.2.1/pure-min.css">-->
<style type="text/css">
* { padding:0; margin:0; font-family:Verdana,sans-serif; }
html, body { height: 100%; background:#000; color:#fff; font-size:20px }
/* table cell spacing/padding reset */
table { border:0; border-collapse:collapse }
table td { padding:0 }
/* meta-classes */
.maxh { height:100% }
.maxw { width:100% }
a { text-decoration:none }
.header { height:20px; background-color:#222; border-bottom:1px solid #333; padding:10px }
.footer { height:5px; background-color:#111; border-top:1px solid #333; }
.list { margin: 0 auto; cursor:default; border:2px solid #333; }
.list .text, .list .link { padding:5px 15px; border:1px solid #222; }
.list .link { width:80px; text-align:center }
.list .text { text-align:left }
.list .text { padding-left:100px }
.list .text.home { background:url('system/img/1280/loader/home.png') 15px center no-repeat }
.list .text.sett { background:url('system/img/1280/loader/settings.png') 15px center no-repeat }
.list .text.vkb { background:url('public/img/1280/menu/icons/def.png') 0 center no-repeat }
.list .text.load { background:url('system/img/1280/loader/net.png') 15px center no-repeat }
.list .text.dlman { background:url('public/img/1280/menu/icons/dm.png') 0 4px no-repeat }
.list .text.pvr { background:url('public/img/1280/menu/icons/pvr.png') 0 5px no-repeat }
.list .text.web { background:url('public/img/1280/menu/icons/web.png') 0 5px no-repeat }
.list .text.favs { background:url('public/img/1280/menu/icons/favs.png') 0 5px no-repeat }
.list .text.help { background:url('public/img/1280/menu/icons/manual.png') 0px 10px no-repeat }
.list tr { height:80px }
.list tr:hover { background-color:#111; }
.list .link:hover { background-color:#8b7f0c; color:#000; font-weight:bold; cursor:pointer }
table.options td.name { font-size:14px; color:grey }
table.options td.data { padding:0 20px 0 5px; }
table.options td.data input[type="text"] { border:none; margin:0; padding:0 5px; height:25px }
</style>
<script type="text/javascript">
function openUrl ( url, width, height ) {
window.open(
url + (url.indexOf('?') === -1 ? '?' : '&') + 'width=' + width + '&height=' + height,
'_blank',
'menubar=0,location=0,resizable=0,scrollbars=0,status=0,titlebar=0,left=0,top=0,width=' + width + ',height=' + height
);
}
var fldServerAddress, fldSessionName;
window.onload = function () {
fldServerAddress = document.getElementById('fldServerAddress');
fldSessionName = document.getElementById('fldSessionName');
fldServerAddress.value = localStorage.getItem('DEBUG_SERVER');
fldSessionName.value = localStorage.getItem('DEBUG_NAME');
fldServerAddress.onchange = function(){
localStorage.setItem('DEBUG_SERVER', this.value);
};
fldSessionName.onchange = function(){
localStorage.setItem('DEBUG_NAME', this.value);
};
};
</script>
</head>
<body>
<table class="maxh maxw">
<tr>
<td class="header">
<table class="options">
<tr>
<td class="name">Proxy server address:</td>
<td class="data"><input type="text" style="width:150px;vertical-align:top" id="fldServerAddress"></td>
<td class="name">Session name:</td>
<td class="data"><input type="text" style="width:100px;vertical-align:top" id="fldSessionName"></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="list">
<tr>
<td class="text home">Service page</td>
<td class="link" onclick="openUrl('services.html', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('services.html', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('services.html', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('services.html', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text sett">System settings</td>
<td class="link" onclick="openUrl('system/settings/index.html', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('system/settings/index.html', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('system/settings/index.html', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('system/settings/index.html', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text load">Portal loader</td>
<td class="link" onclick="openUrl('system/pages/loader/index.html', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('system/pages/loader/index.html', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('system/pages/loader/index.html', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('system/pages/loader/index.html', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text dlman">Download manager</td>
<td class="link" onclick="openUrl('public/app/dlman/index.html', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('public/app/dlman/index.html', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('public/app/dlman/index.html', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('public/app/dlman/index.html', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text pvr">Record manager</td>
<td class="link" onclick="openUrl('public/app/pvr/index.html', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('public/app/pvr/index.html', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('public/app/pvr/index.html', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('public/app/pvr/index.html', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text web">Internet browser</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=2', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=2', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=2', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=2', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text favs">Internet bookmarks</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=1', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=1', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=1', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('public/app/ibman/index.html?mode=1', 720, 480)">NTSC</td>
</tr>
<tr>
<td class="text help">Help</td>
<td class="link" onclick="openUrl('public/app/help/index.html', 1920, 1080)">1080p</td>
<td class="link" onclick="openUrl('public/app/help/index.html', 1280, 720)">720p</td>
<td class="link" onclick="openUrl('public/app/help/index.html', 720, 576)">PAL</td>
<td class="link" onclick="openUrl('public/app/help/index.html', 720, 480)">NTSC</td>
</tr>
</table>
</td>
</tr>
<!--<tr>
<td class="footer">
footer
</td>
</tr>-->
</table>
</body>
</html>

31
mag/events.txt Normal file
View File

@ -0,0 +1,31 @@
//All global events
//Reload given window
"window.reload"
//Load given URL (has 1 param {String} - new window URL)
"window.load"
// Player end playing some file
"player.end"
// Play file. (has 1 param {String} - file url)
"player.play"
// usb device has been mounted
"broadcast.storage.mount"
// accessControl state has been change
"broadcast.accessControl"
// usb device has been unmounted
"broadcast.storage.unmount"
// sent (wake up) device to (from) standby mode
"portal.standbyMode"
// reload environment variables
"environment.reload"
// reset player resolution data according to new video mode
"video.mode.reload"

708
mag/history.md Normal file
View File

@ -0,0 +1,708 @@
History
=======
## 2020.08.14 ##
* enable bluetooth support only for specific devices
* force disable bluetooth and clear env for unsupported devices
## 2020.07.21 ##
* delete Magic Cast application
## 2020.07.03 ##
* fix update resolution on HDMI connect event
* fix review warnings
## 2020.06.25 ##
* add IM4411WV model support
* add IM4410WV model support
## 2020.06.04 ##
* remove overlapping of bookmarks modal by autocomplete
* fix logic of changing F3 footer button
* initialize Widevine for IPTV playlists if allowed
* fix handle focus on items in Explorer
* remove selection from added items inside Favorites
* add support for whole cyrillic letters range in URL validation
## 2020.05.07 ##
* add implementation for external page loading delay
* select view as uniq to prevent loosing text
* add check condition for setting delay
* encode input fragment only for search mode
## 2020.04.23 ##
* switch by default to the highest qulity for HLS
## 2020.04.21 ##
* fix obtain "addresses" property for mount config
## 2020.04.14 ##
* add SRT as stream protocol in URL validator, refactor
## 2020.04.10 ##
* add basic support for Widevine DRM playlists
* fix manual mounting of SMB share
## 2020.03.26 ##
* encode URL spaces and pluses (+) in appropriate way
* remove unescaping of explicit URL encoding symbols
## 2020.03.11 ##
* fix reaction when error occured during slideshow
## 2020.03.04 ##
* switch to HTTPS for update lists
## 2020.01.23 ##
* add IM4411V model support
* fix demo page loading by preventing parse wrong font files
## 2019.10.31 ##
* fix help generator
* add sorting by number in m3u parser
## 2019.10.18 ##
* add device reload after user data cleared
* fix server part of help-generator for php 7 version
* fix background after removing all channels
## 2019.10.11 ##
* fix timeshift start error modal
## 2019.10.09 ##
* skip privacy policy not only in loader but in portal too
## 2019.09.26 ##
* fix hiding modal behavior to prevent from show webinput results
* prevent of showing webinput result box on exit from menu by Exit button
* fix mounting share by domain name, remove IP validation
* improve code quality
## 2019.09.03 ##
* fix review warnings
* fix checkbox styles for 576 and 480 resolution
## 2019.08.19 ##
* fix teletext in 4k resolution
## 2019.08.14 ##
* fix initial mute state after reload portal
* add 4k resolution for MAG422
## 2019.08.06 ##
* portals loader: add privacy policy reset
* fix focus item in IPTV Channels after empty list
## 2019.07.25 ##
* fix update list url for IM2101VO
## 2019.07.05 ##
* fix init volume setting change
## 2019.07.04 ##
* portals loader: remove HEAD request from portal availability check and use only GET request (some clients have strangely configured servers)
## 2019.07.01 ##
* player: fix jscs
* player: don't show error message for same file twice
* player: exit from player after error message for bad images in non-slideshow mode
* player: show error message for bad images
## 2019.06.12 ##
* loader: fix embedded portal loading in multiportal mode
* loader: fix jscs
## 2019.06.10 ##
* loader: fix jscs
* loader: remove exit button from privacy policy
* loader: add checks for different ajax errors, fix abort function in ajax
* loader: fix interface
## 2019.06.05 ##
* loader: add new exit button
* fix teletext option setup for low resolutions instead of low video modes
* help: add privacy policy agreement
* help generator: update to php 7
* fix player teletext settings saving
* fix navigation in player teletext settings
## 2019.05.30 ##
* remove tif format support from mag322
* loader: fix long names problems
## 2019.05.17 ##
* fix loader
## 2019.05.08 ##
* remove tif format for mag322
* loader page rework and optimizations
## 2019.04.25 ##
* fix list vertical align in DVB channels
## 2019.04.18 ##
* add IM2101VO model support
* remove .raw format support for mag322
## 2019.04.11 ##
* add IM4411 model support
## 2019.03.27 ##
* add IM4412 model support
* add IM2101VI model support
## 2019.03.25 ##
* remove some user data from speedtest and traceroute reports for aura
## 2019.02.13 ##
* fix advanced settings in access control
* add 4k resolution for MAG420
* fix wifi manual settings
* fix set subtitles black color
* fix load manual wifi settings
## 2019.02.07 ##
* fix weather in master settings
## 2019.01.28 ##
* fix text in popup which appears for blocked portals
## 2019.01.22 ##
* fix name overlap in update modal
* add 'utf-16be' and 'utf-16le' subtitles encoding
* fix fast load in loader
* fix access control in loader
## 2019.01.02 ##
* fix update start
## 2018.12.27 ##
* update exit_wraper_bg.png from 2x2 to 100x100 size
* fix event handler in update modal
## 2018.12.10 ##
* support difference between mag254 and mag322 wifi event status implementation
* add mag420 model support
## 2018.12.05 ##
* correct updateList for MAG422
## 2018.11.30 ##
* fix UPnPRendererClear error
* change keydown listener to keypress in tattelecom code
* update dvb scanning modals
## 2018.11.15 ##
* fix focused out of array
* fix code style
## 2018.11.07 ##
* add mag422, remove PPPoE for mag422, mag424, mag425 from system settings
## 2018.10.30 ##
* fix error handler for playlist update request
* remove forcing enabling service button
* hide unsupported settings for IM2100V, IM2100VI (resolution and network settings)
## 2018.09.18 ##
* add contact data to warning text at "url is blocked" page
* add IM2100VI model support
## 2018.09.07 ##
* add check for async work of bluetooth API function at mag424 (stbBluetooth.enable)
* fix channels list loading
* fix start play object without url in player
## 2018.08.23 ##
* fix event propagation
## 2018.08.21 ##
* update manual
* update localization
* fix empty audio_initial_volume state
## 2018.08.13 ##
* fix change position
## 2018.08.07 ##
* fix localization
## 2018.07.30 ##
* fix saving zero volume
* fix localization
## 2018.07.19 ##
* disable stbUPnPRenderer and clear code
## 2018.07.11 ##
* fix current image date check in update
## 2018.06.01 ##
* increase portal loading delay in multiportal mode to fix slow wifi start
## 2018.05.24 ##
* add IM2100V model support
* remove games from portal
* remove games section from manual
## 2018.05.17 ##
* fix update check: remove influence of device local time zone
## 2018.05.07 ##
* fix incorrectly encoded urls in API event
## 2018.04.27 ##
* add IM2101 device support
* fix navigation in favorite, fix style in DVB Channels
## 2018.04.24 ##
* remove DVB settings for IM2102
* fix navigation in DVB channels
* fix DVB channels item style
## 2018.04.13 ##
* fix access control settings
## 2018.04.12 ##
* add modal window with info on url blocking
## 2018.04.10 ##
* add IM2102 device support
## 2018.04.03 ##
* add IM2100 device support
* change title LED brightness (standby) in settings
* add stbUPnP.deinit in system settings
## 2018.03.26 ##
* add MAG424 device support
* fix checkbox style in settings
* correct configs for MAG424/425/351/352
## 2018.02.19 ##
* add new timezone codes
* always check environment variables portal1 and portal2 for possible operator changes (and apply them)
* change statistic server url
* optimise auto update requests
* disable 1920x1080 graphic resolution for AuraHD4
## 2018.02.16 ##
* fix translation
* fix opening Home Media resources after UPnP failure
* fix retrieving search data from Google for autocomplete
* improve saving algorithm in timeshift
* don't show auto power down if timeshift is active
* renew environment variables values after correction by operator
## 2018.01.24 ##
* remove 1080p resolution selection in settings for mag322
## 2018.01.19 ##
* request timeout for retrieving the help archive has been increased
* fix video settings
* fix wifi keys generation page
## 2018.01.09 ##
* fix mounting share by hand
* remove DVB setting for AuraHD4
## 2017.12.26 ##
* fix wrong url for auto update on MAG276
* remove misspelling from auto update url in auraHD4
* comment cleanup trash download tasks for unmounted storages (cleanup triggers by unmount event)
* cleanup trash download tasks for unmounted storages (cleanup triggers by unmount event)
## 2017.12.18 ##
* fix value parsing for auto update condition variable
## 2017.11.29 ##
* add missing codec image to cache list
* fix item focusing in media browser on player event
* fix missing environment variables for sending headers on update
* optimize player and explorer pages switching
## 2017.11.27 ##
* add new headers (X-Portal1 and X-Portal2) in update list request
* fix save resolution in settings
* don't send update check request after update modal window exit
## 2017.11.20 ##
* add new headers in update list request
* disable password field for NFS mounting
* change logo for AuraHD 4
## 2017.11.17 ##
* add AC3+ audio type
* fix interface error in download app on quick multiple tasks creation
* add speed test for mag35*
## 2017.11.07 ##
* remove PPPoE for AuraHD*
* update updateList url for MAG256 and MAG351
## 2017.10.30 ##
* fix reload portal after change settings
## 2017.10.13 ##
* add untune dvb input in DVB channels
* fix focus item in Media Browser
* correct supported files types list for mag322
## 2017.09.28 ##
* add AuraHD4 device config and logo
* fix pause icon in download manager
* fix reload portal after change settings
* fix teletext settings
* add logo for mag425
## 2017.09.14 ##
* fix reboot device after reset settings
* fix problem with chapters list in player for DVD content
* fix reload portal message after reset settings
* add mag324c and mag325c logo images
## 2017.09.04 ##
* add mag324c and mag325c logo images
## 2017.08.28 ##
* fix wifi, internet and network states
* update localizations
* add .wtv extension to supported files
## 2017.08.17 ##
* fix mag349 config
* change format wifi_off from boolean to number
* update registers types in config for mag3** series
* fix wifi state change
## 2017.08.11 ##
* add wifi disable button and state change hook
* fix enable wifi button state
## 2017.08.09 ##
* fix ts time save
* add to settings information about rootFS version
* fix update url for mag324c
* remove 'No ip' settings for MAG322, MAG324C
## 2017.07.28 ##
* fix editing iptv channels, remove unc option from SMB mount
## 2017.07.26 ##
* remove PPPoE from network settings on MAG324C
## 2017.07.25 ##
* fix adding channels to IPTV playlist
* checking API version for set appropriate method signatures on open samba host
* fix unc address syntax on cifs mount
## 2017.07.24 ##
* add hash info to build metadata
* add MAG324C model support
* protect parsing AJAX request for update list result
* remove PPPoE from settings for MAG322
## 2017.07.14 ##
* add auth for SMB servers and rework error handling
* fix tv url parsing
* hide password and fix mounting share by hand
* fix manual mounting in SAMBA browser
* store auth data of successful connections to SMB servers
* open SAMBA server even if it's password protected
## 2017.06.23 ##
* hide info panel on bluetooth disable
* realize opening shares with multiple IPs
## 2017.06.14 ##
* add mac to auto update list request as query param
## 2017.05.22 ##
* add warning message in case of NAND bank damage
* show actual NAND number in settings (with emergency status info)
## 2017.05.15 ##
* add MAGic Cast menu item
* fix bluetooth adapter disabling when some device is connected
* fix .m3u parser
* fix audio playing info panel state in player
## 2017.04.26 ##
* add "wtv" video file format support
## 2017.04.25 ##
* fix playback on video mode change
* fix empty Bluetooth device list handlers
## 2017.04.14 ##
* set dynamic range compression for DolbyDigital audio on player initialization
* remove "Dynamic range compression" option from settings
* restrict "Operating mode" audio setting to "RF Mode" and "Line Mode" only
## 2017.04.12 ##
* update codec icons in player
## 2017.04.05 ##
* correct manual localization
## 2017.03.31 ##
* fix selected chapter after change position in DVD or ISO files
* fix #6534, read cue and m3u playlists equally
* remove dead code (variable STB_MODE_STANDBY) and fix multiple net status function call
* add flag IPTV_PLAYBACK_ON_START to start first channel in full screen
## 2017.03.29 ##
fix usb unmount when something is playing
## 2017.03.28 ##
* save bluetooth enabled state in environment
* remove unused device characteristics
## 2017.03.27 ##
* fix player preview position
* bluetooth: sort devices by paired and active
* fix bug with partially transparent overlay
* fix localization
## 2017.03.16 ##
* add device config to json generator
* add devices logos
* add bluetooth translations
* rework bluetooth api
* add MAG323 model support
* fix image preview
* fix subtitles and teletext subtitles
* add rotate image in player menu
* fix localisation
## 2017.03.01 ##
* Add MAG324/MAG325 device support
* Add img format #11116
* Solve #11048
## 2017.02.22 ##
* hide gSTB error message until we get localisation for it
* title field shouldn't rewrite lang field and if title field available use it instead of localised type text
* upgrade error page ping

14
mag/index.html Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>new MAG 200-250</title>
<script type="text/javascript">
window.location = 'system/pages/loader/index.html';
</script>
</head>
<body>
</body>
</html>

32
mag/rules.js Normal file
View File

@ -0,0 +1,32 @@
'use strict';
/**
* Customization rules for manual tune
* @author Stanislav Kalashnik <sk@infomir.eu>
* @namespace
*/
var RULES = {
'Playback' : true,
'Interface' : true,
'SoftwareAutoUpdate': true,
'TimeShift' : true,
'SpeedTest' : true,
'Traceroute' : true,
'SystemSettings' : true,
'SetupWizard' : true,
'DVB' : true,
'accessControl' : true,
'teletext' : true
};

795
mag/services.html Normal file
View File

@ -0,0 +1,795 @@
<!doctype html>
<html>
<head>
<title>STB Service page</title>
<meta charset='utf-8'>
<script>
var PATH_BASE = '';
</script>
<script type="text/javascript" src="system/init.js"></script>
<script type="text/javascript">
(function () {
var time = (new Date).getTime();
// conditional css loading
document.write('<link rel="stylesheet" href="system/' + WINDOW_HEIGHT + '.css?_=' + time + '">');
document.write('<link rel="stylesheet" href="public/portal/' + WINDOW_HEIGHT + '.css?_=' + time + '">');
})();
</script>
<script type="text/javascript" src="rules.js"></script>
<script type="text/javascript" src="system/config.js"></script>
<script type="text/javascript" src="system/wm.js"></script>
<script type="text/javascript" src="system/keys.js"></script>
<script type="text/javascript" src="system/gettext.js"></script>
<script type="text/javascript" src="system/tools.js"></script>
<script type="text/javascript" src="system/cbase.js"></script>
<script type="text/javascript" src="system/update.js"></script>
<script type="text/javascript" src="system/cprogressbar.js"></script>
<script type="text/javascript" src="system/cpage.js"></script>
<script type="text/javascript" src="system/cslist.js"></script>
<script type="text/javascript" src="system/clist.js"></script>
<script type="text/javascript" src="system/vscrollbar.js"></script>
<script type="text/javascript" src="system/vlist.js"></script>
<script type="text/javascript" src="system/cgmenu.js"></script>
<script type="text/javascript" src="system/cmodal.js"></script>
<script type="text/javascript" src="system/cbpanel.js"></script>
<script type="text/javascript" src="system/cbcrumb.js"></script>
<script type="text/javascript" src="system/csbar.js"></script>
<script type="text/javascript" src="system/buffer.js"></script>
<script type="text/javascript" src="system/ccheckbox.js"></script>
<script type="text/javascript" src="system/cinput.js"></script>
<script type="text/javascript" src="system/cselect.js"></script>
<script type="text/javascript" src="system/clog.js"></script>
<script type="text/javascript" src="system/cupdatemodal.js"></script>
<script type="text/javascript" src="system/cmap.js"></script>
<script type="text/javascript" src="system/timezones.js"></script>
<script type="text/javascript" src="system/keyboard/js/config.js"></script>
<script type="text/javascript" src="system/access.control/main.js"></script>
<script type="text/javascript" src="system/emiter.js"></script>
<script type="text/javascript" src="system/wamp.js"></script>
<script type="text/javascript" src="public/portal/types.js"></script>
<script type="text/javascript" src="public/portal/vars.js"></script>
<script type="text/javascript" src="system/variables/check.js"></script>
<script type="text/javascript" src="public/portal/services.js"></script>
<script type="text/javascript" src="public/portal/speedtest.js"></script>
<script type="text/javascript" src="public/portal/menu.js"></script>
<script type="text/javascript" src="public/config.js"></script>
<script type="text/javascript" src="public/portal/media/browsers/file.js"></script>
<script type="text/javascript" src="public/portal/media/browsers/upnp.js"></script>
<script type="text/javascript" src="public/portal/media/cflist.js"></script>
<script type="text/javascript" src="public/portal/media/tvlist.js"></script>
<script type="text/javascript" src="public/portal/media/dvblist.js"></script>
<script type="text/javascript" src="public/portal/media/epggrid.js"></script>
<script type="text/javascript" src="public/portal/media/dvbepg.js"></script>
<script type="text/javascript" src="public/portal/media/exlporer.js"></script>
<script type="text/javascript" src="public/portal/media/iptv.js"></script>
<script type="text/javascript" src="public/portal/media/dvbtv.js"></script>
<script type="text/javascript" src="public/portal/media/modals.js"></script>
<script type="text/javascript" src="public/portal/media/main.js"></script>
<script type="text/javascript" src="public/portal/media/player.js"></script>
<script type="text/javascript" src="public/portal/media/playlist.js"></script>
<script type="text/javascript" src="public/portal/media/upnpRender.js"></script>
<!--<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=places,weather&scale=2&language=en"></script>-->
<style type="text/css">
html, body { overflow:hidden; background:transparent; color:#fff; margin:0; padding:0; -webkit-user-select:none; font-family:Ubuntu,sans-serif; }
/* table cell spacing/padding reset */
table { border:0; border-collapse:collapse; border-spacing:0; }
table td { padding:0 }
/* meta-classes */
.maxh { height:100% }
.maxw { width:100% }
a { text-decoration:none }
/* scroll bars */
::-webkit-scrollbar-track { background:#2a2c2f }
::-webkit-scrollbar-thumb { background:#ffc20e }
.page#pageServiceMenu .header { position:absolute; top:0; background:none; z-index:7 }
#cursorGround { z-index:1 }
#cursor { z-index:1 }
#ground { z-index:2 }
#weatherSettings { z-index:3 }
.page#pageMediaPlayer #slideContainer {
position: absolute;
/*background-color: black;*/
width: 100%;
height: 100%;
top: 0;
left: 0;
text-align: center;
}
.page#pageMediaPlayer #slideContainer .fix {
width: 0;
height: 100%;
overflow: hidden;
display: inline-block;
vertical-align: middle;
text-align: left;
}
.page#pageMediaPlayer .animationContainer {
margin: 0 auto;
width: 500px;
height: 162px;
display: inline-block;
vertical-align: middle;
overflow: hidden;
text-align: left;
}
.page#pageMediaPlayer .slide{
position: absolute;
-webkit-animation-name: play;
-webkit-animation-iteration-count: infinite;
-webkit-animation-duration: 0.8s;
opacity: 0;
/*opacity:1;*/
}
@-webkit-keyframes play{
/*from{opacity: 1;}*/
0% { opacity: 0; }
10% { opacity: 1; }
40% { opacity: 1; }
100% { opacity: 0; }
/*to{opacity: 1;}*/
}
.page#pageMediaPlayer .animationPlay4 { -webkit-animation-delay: 0s; }
.page#pageMediaPlayer .animationPlay3 { -webkit-animation-delay: 0.2s; }
.page#pageMediaPlayer .animationPlay2 { -webkit-animation-delay: 0.4s; }
.page#pageMediaPlayer .animationPlay1 { -webkit-animation-delay: 0.6s; }
/*
fix resizing bug after showing table, Bug #2281, link - http://192.168.1.220:3000/issues/2281
looks like a browser bug
*/
.page#pageMediaPlayer .cgmenu-main table {table-layout: fixed;}
</style>
</head>
<body id="body">
<div id="loading" style="width:100%; height:100%; background-color:transparent; position:absolute; top:0; left:0; z-index:2010; display:block; cursor:none">
<span style="position:absolute; color:#ccc; font-family:Ubuntu,sans-serif; font-size:36px; width:100%; text-align:center; top:50%; cursor:none">Loading...</span>
</div>
<!-- Master Settings -->
<div id="pageMasterSettings" style="display: none;">
<div id="pageMasterSettings_header"></div>
<div id="pageMasterSettings_main" class=""></div>
<div id="pageMasterSettings_footer"></div>
<!-- google map -->
<div id="masterSettingsMapCanvas" class="mapCanvas"></div>
<!-- end google map -->
</div>
<!-- end Master Settings -->
<!-- Weather Settings -->
<div id="weatherSettings" style="display:none" class="page">
<!-- main container -->
<table cellpadding="0" cellspacing="0" border="0" style="width:100%; height:100%; background-color:transparent" class="body">
<!-- page body top panel -->
<tr class="header">
<td colspan="3" class="crop">
<table class="maxw" cellpadding="0" class="maxw" cellspacing="0" border="0">
<tr>
<!-- Breadcrumb component -->
<td class="cbcrumb"></td>
<!-- Search bar component -->
<td class="csbar">
<input type="text" id="place"/>
</td>
</tr>
</table>
</td>
</tr>
<!--<tr class="map" style="display:none">-->
<!--<td colspan="3">-->
<!--<div class="canvas"></div>-->
<!--</td>-->
<!--</tr>-->
<tr class="content">
<td colspan="2" class="today">
<!-- today -->
<table id="wsbody_today" cellpadding="0" cellspacing="0" border="0">
<tr class="row_title">
<td colspan="2" align="left">
<div class="day" id="forecast_day_0_day"></div>
<div class="date" id="forecast_day_0_date"></div>
</td>
</tr>
<tr class="row_image">
<td colspan="2" class="image" align="center" style="vertical-align:middle">
<div id="forecast_day_0_img"></div>
</td>
</tr>
<tr class="row_descr">
<td colspan="2">
<div class="descr" id="forecast_day_0_cond"></div>
</td>
</tr>
<tr class="row_data">
<td>
<div class="weather_details day_temp" id="forecast_day_0_to">0</div>
</td>
<td>
<div class="weather_details humidity" id="forecast_day_0_hum">0%</div>
</td>
</tr>
<tr class="row_data" align="left">
<td>
<div class="weather_details night_temp" id="forecast_day_0_from">0</div>
</td>
<td>
<div class="weather_details wind" id="forecast_day_0_wind"></div>
</td>
</tr>
<tr class="row_footer">
<td colspan="2">&nbsp;</td>
</tr>
</table>
<!-- end today -->
</td>
<td class="weather_list">
<!-- list of the next 3 days -->
<table id="wsbody_wlist" cellpadding="0" cellspacing="0" border="0">
<tr>
<td align="left">
<div class="day" id="forecast_day_1_day"></div>
<div class="date" id="forecast_day_1_date"></div>
</td>
<td class="image">
<div id="forecast_day_1_img"></div>
</td>
<td>
<div class="descr" id="forecast_day_1_cond">0</div>
</td>
<td>
<div class="day_temp" id="forecast_day_1_to">0</div>
<div class="night_temp" id="forecast_day_1_from">0</div>
</td>
</tr>
<tr>
<td align="left">
<div class="day" id="forecast_day_2_day"></div>
<div class="date" id="forecast_day_2_date"></div>
</td>
<td class="image">
<div id="forecast_day_2_img"></div>
</td>
<td>
<div class="descr" id="forecast_day_2_cond">0</div>
</td>
<td>
<div class="day_temp" id="forecast_day_2_to">0</div>
<div class="night_temp" id="forecast_day_2_from">0</div>
</td>
</tr>
<tr>
<td align="left">
<div class="day" id="forecast_day_3_day"></div>
<div class="date" id="forecast_day_3_date"></div>
</td>
<td class="image">
<div id="forecast_day_3_img"></div>
</td>
<td>
<div class="descr" id="forecast_day_3_cond">0</div>
</td>
<td>
<div class="day_temp" id="forecast_day_3_to">0</div>
<div class="night_temp" id="forecast_day_3_from">0</div>
</td>
</tr>
</table>
<!-- end list of the next 3 days -->
</td>
</tr>
<tr class="footer">
<td class="crop exit">
<div class="cbpanel-main"></div>
<!--<div onclick="weather.weatherSettingsExit()">Exit</div>-->
</td>
<td class="crop main" colspan="2">
<!-- control buttons block -->
<div class="cbpanel-main"></div>
</td>
</tr>
</table>
<!-- end main container -->
<!-- autocompleter list -->
<div class="suggests" id="suggests" style="display:none">
<ul>
<li id="s0"></li>
<li id="s1"></li>
<li id="s2"></li>
<li id="s3"></li>
<li id="s4"></li>
</ul>
</div>
<!-- end autocompleter list -->
<!-- google map -->
<div id="mapCanvas" class="mapCanvas"></div>
<!-- end google map -->
</div>
<!-- end Weather Settings -->
<!-- Service Menu -->
<div class="page" id="pageServiceMenu">
<div class="bg"></div>
<div class="header">
<div id="statuses">
<div id="network_status"></div>
<div id="wifi_status"></div>
<div id="lan_status"></div>
</div>
<div id="screenClockHours_main" class="date_time" style="text-align:center">
<div class="time" id="screenClockMinutes_main"></div>
<div id="screenClockDate_main" class="date"></div>
</div>
<div id="face" style="text-align:right"></div>
<div id="weather_condition" class="weather_default" style="text-align:right"></div>
</div>
<div id="switch_desktop" onclick="app.switch_page()">
<div id="cur_desktop" class="_0"></div>
</div>
<div id="cursorGround" class="ground0">
<div id="cursor"></div>
</div>
<div id="ground" class="ground0"></div>
</div>
<!-- end Service Menu -->
<!-- Settings -->
<div class="page" id="pageSettings">
<table class="body">
<!-- page body top panel -->
<tr class="header">
<td colspan="2" class="crop">
<table class="maxw">
<tr>
<!-- Breadcrumb component -->
<td class="cbcrumb"></td>
<!-- Search bar component -->
<td class="csbar"></td>
</tr>
</table>
</td>
</tr>
<!-- page body main content block -->
<tr class="content">
<td colspan="2" class="crop">
<!-- FileList component -->
<div class="cslist-main maxw"></div>
</td>
</tr>
<!-- page body bottom panel -->
<tr class="footer">
<td class="crop exit">
<div class="cbpanel-main"></div>
<!--<div onclick="SettingsPage.pressExit()">Exit</div>-->
</td>
<td class="crop main">
<!-- control buttons block -->
<div class="cbpanel-main"></div>
</td>
</tr>
</table>
</div>
<!-- end Settings -->
<!-- IPTV -->
<div class="page" id="pageTVChannels">
<!-- side menu hidden body -->
<div class="cgmenu-main"></div>
<!-- main page body -->
<table class="body">
<!-- page body top panel -->
<tr class="header">
<td colspan="2" class="crop">
<table class="maxw">
<tr>
<!-- Breadcrumb component -->
<td class="cbcrumb"></td>
<!-- Search bar component -->
<td class="csbar"></td>
</tr>
</table>
</td>
<td class="crop tray"></td>
</tr>
<tr class="content" style="background-image: url(system/img/backgrounds/bg_black_70.png);">
<td colspan="3" class="crop">
<table class="maxw">
<tr>
<td class="main">
<!-- FileList component -->
<div class="cslist-main"></div>
</td>
<td class="content_right">
<div class="content">
<div class="title"><div class="info_icon"></div><div class="infoTitle"></div></div>
<div class="prog_name URL" style="word-break: break-all;word-wrap: break-word;"></div>
<div class="prog_name pvrStatus" style="word-break: break-all;word-wrap: break-word; display: none;">
<div class="pvrText" style="float:left;"></div>
<div class="pvrStatusImg done"></div>
<div class="pvrStatusImg wait"></div>
<div class="pvrStatusImg write"></div>
<div class="pvrStatusImg error"></div>
</div>
<div class="prog_name epgNow"></div>
<div class="prog_name epgNext"></div>
</div>
</td>
</tr>
</table>
</td>
</tr>
<!-- page body bottom panel -->
<tr class="footer">
<td class="crop exit">
<div class="cbpanel-main"></div>
<!--<div onclick="IPTVChannels.actionExit()">Exit</div>-->
</td>
<td class="crop main" colspan="2">
<!-- control buttons block -->
<div class="cbpanel-main"></div>
</td>
</tr>
</table>
<div class="channelNumber" style="display: none;"></div>
</div>
<!-- end IPTV -->
<!-- DVBTV -->
<div class="page" id="pageDVBChannels">
<!-- side menu hidden body -->
<div class="cgmenu-main"></div>
<div class="scanInProgress maxw maxh" style="display: none;">
<div class="connection">
<div class="percent percentScan">100%</div>
<div class="loader"></div>
</div>
<div class="desc">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="titleFreqScan" style="text-align: right;width: 50%;"></td>
<td class="titleFreqScanText" style="text-align: left;width: 50%;"></td>
</tr>
<tr>
<td class="titleTotalScan" style="text-align: right"></td>
<td class="titleTotalScanText" style="text-align: left"></td>
</tr>
<tr>
<td class="titleLastScan" style="text-align: right"></td>
<td class="titleLastScanText" style="text-align: left"></td>
</tr>
</table>
</div>
</div>
<!-- main page body -->
<table class="body">
<!-- page body top panel -->
<tr class="header">
<td colspan="2" class="crop">
<table class="maxw">
<tr>
<!-- Breadcrumb component -->
<td class="cbcrumb"></td>
<!-- Search bar component -->
<td class="csbar"></td>
</tr>
</table>
</td>
<td class="crop tray"></td>
</tr>
<!-- page body main content block -->
<tr class="content" style="background-image: url(system/img/backgrounds/bg_black_70.png);">
<td colspan="3" class="crop">
<table class="maxw">
<tr>
<td class="main">
<!-- FileList component -->
<div class="clist-main"></div>
</td>
<td class="content_right">
<div class="content">
<div class="title"><div class="info_icon"></div><div class="infoTitle"></div></div>
<div class="prog_name epgNow"></div>
<div class="prog_name epgNext"></div>
</div>
</td>
</tr>
</table>
</td>
</tr>
<!-- page body bottom panel -->
<tr class="footer">
<td class="crop exit">
<div class="cbpanel-main"></div>
</td>
<td class="crop main" colspan="2">
<!-- control buttons block -->
<div class="cbpanel-main"></div>
</td>
</tr>
</table>
<div class="channelNumber" style="display: none;"></div>
</div>
<!--DVB EPG PAGE-->
<div class="page" id="pageDVBEpg">
<!-- main page body -->
<table class="body">
<!-- page body top panel -->
<tr class="header">
<td colspan="2" class="crop">
<table class="maxw">
<tr>
<!-- Breadcrumb component -->
<td class="cbcrumb"></td>
</tr>
</table>
</td>
</tr>
<!-- page body main content block -->
<tr class="content" style="background-image: url(system/img/backgrounds/bg_black_70.png);">
<td colspan="3" class="crop">
<table class="maxw">
<tr>
<td colspan="2" class="timeblocks">
<!--<div class="mainblock"></div>-->
</td>
<td>
<div class="clock"></div>
</td>
</tr>
<tr>
<td valign="top" class="clist-main" colspan="3"><div class="timeline"></div></td>
</tr>
<tr>
<td colspan="2">
<div class="current_prog"></div>
</td>
</tr>
</table>
</td>
</tr>
<!-- page body bottom panel -->
<tr class="footer">
<td class="crop exit">
<div class="cbpanel-main"></div>
<!--<div onclick="DVBEpg.actionExit()">Exit</div>-->
</td>
<td class="crop main" colspan="2">
<!-- control buttons block -->
<div class="cbpanel-main"></div>
</td>
</tr>
</table>
<div class="channelNumber" style="display: none;"></div>
</div>
<!-- end DVBTV -->
<!-- Media Browser -->
<div class="page" id="pageMediaBrowser">
<!-- side menu hidden body -->
<div class="cgmenu-main"></div>
<!-- main page body -->
<table class="body">
<!-- page body top panel -->
<tr class="header">
<td colspan="2" class="crop">
<table class="maxw">
<tr>
<!-- Breadcrumb component -->
<td class="cbcrumb"></td>
<!-- Search bar component -->
<td class="csbar"></td>
</tr>
</table>
</td>
<td class="crop tray"></td>
</tr>
<!-- page body main content block -->
<tr class="content">
<td colspan="3" class="crop">
<table class="maxw">
<tr>
<td class="main">
<!-- FileList component -->
<div class="vlist-main"></div>
<div class="vscroll"></div>
</td>
<td class="sbar">
<!-- SideBar component -->
<table class="maxh maxw">
<tr>
<td class="view">
<!-- main preview block -->
</td>
</tr>
<tr>
<td class="info">
<div class="block all">
<span class="title">Records:</span> <span class="value">0</span>
</div>
<div class="block sel">
<span class="title">Selected:</span> <span class="value">0</span>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<!-- page body bottom panel -->
<tr class="footer">
<td class="crop exit">
<div class="cbpanel-main"></div>
<!--<div onclick="MediaBrowser.actionBack()">Exit</div>-->
</td>
<td class="crop main" colspan="2">
<!-- control buttons block -->
<div class="cbpanel-main"></div>
</td>
</tr>
</table>
</div>
<!-- end Media Browser -->
<!-- Tools Pan -->
<div id="toolsPan">
<table cellpadding="0" cellspacing="0" width="100%" border="0" class="fixed">
<tr>
<td id="media_HeaderContainer" valign="top">
<!--<div id="mediaHeader_DualMonoIco" class="mediaHeaderIco"></div>-->
<!--<div id="mediaHeader_PauseIco" class="mediaHeaderIco"></div>-->
<div id="mediaHeader_Aspect" class="mediaHeaderIco">
<div class="aspect_icon"></div>
<span></span>
</div>
</td>
<td class="volumeContainer">
<div id="mute" style="visibility:hidden"></div>
<div id="volumeForm" style="visibility:hidden">
<div id="volume_bar">
<img src="" class="alignLeft" id="volumeLeft" alt="" style="float:left">
<div id="volume_right"></div>
</div>
<div id="volume_num"></div>
</div>
</td>
</tr>
</table>
</div>
<!-- end Tools Pan -->
<!-- MediaPlayer -->
<div class="page" id="pageMediaPlayer">
<div id="slideContainer" style="display:none;">
<div class="animationContainer">
<img class='slide animationPlay1' src="public/img/1280/media/radio_slide_1.png" alt="" />
<img class='slide animationPlay2' src="public/img/1280/media/radio_slide_2.png" alt="" />
<img class='slide animationPlay3' src="public/img/1280/media/radio_slide_3.png" alt="" />
<img class='slide animationPlay4' src="public/img/1280/media/radio_slide_4.png" alt="" />
</div>
<div class="fix"></div>
</div>
<div class="clockOptional" id="playerClockOptional">00:00</div>
<div class="player_header" style="visibility: hidden;position: absolute;" id="playerHeader">
<div class="exit_bg">
<a href="#" class="exit" id="playerHeaderExit" onclick="MediaPlayer.exit();return false;"></a>
</div>
<a href="#" class="hideplayer" id="playerHideplayer" onclick="MediaPlayer.showInfo(); event.stopPropagation(); return false;"></a>
<a href="#" class="settings" id="playerHeaderSetting" onclick="MediaPlayer.ModalMenu.Show(); event.stopPropagation(); return false;"></a>
<div class="clock" id="playerClock"></div>
<a href="#" class="blue" id="playerHeaderBlue" onclick="MediaPlayer.actionF3(); event.stopPropagation(); return false;"></a>
<a href="#" class="hideplist" id="playerHideplist" onclick="MediaPlayer.actionF2(); event.stopPropagation(); return false;"></a>
</div>
<div class="player_footer" style="visibility: hidden;position: absolute;" id="playerFooter">
<div class="seekbar" id="playerBar">
<div class="progress" id="playerProgressBar"></div>
<div class="preload" id="playerBufferBar"></div>
</div>
<div>
<a href="#" class="play-pause" id="playerPause" onclick="MediaPlayer.playPause(); event.stopPropagation(); return false;"></a>
<a href="#" class="rew" id="playerREW" onclick="MediaPlayer.setPos(-1); event.stopPropagation(); return false;"></a>
<a href="#" class="ffwd" id="playerFFWD" onclick="MediaPlayer.setPos(1); event.stopPropagation(); return false;"></a>
<div class="name" id="playerTitle"></div>
<div class="time_total" id="playerTotalTime"></div>
<div class="slash" id="playerSlash">/</div>
<div class="time_cur" id="playerCurrentTime"></div>
</div>
</div>
<div class="cright" id="cright" style="display: none;">
<div class="box">
<img src="" id="audioType" style="float:left;"/>
<div id="audioText" style="float:left;"></div>
</div>
</div>
<div class="cright_bottom">
<div class="box" id="cright_bottom_tvtext" style="display: none;">
<div class="tvtext_icon"></div>
</div>
<div class="box" id="cright_bottom_sub" style="display: none;">
<div class="sub_ico"></div>
<div id="subText" style="float:left;"></div>
</div>
</div>
<div class="cright_hls" id="cright_hls" style="display: none;">
<div class="box">
<div id="hlsInfo" style="float:left;">HLS info</div>
</div>
</div>
<div class="cgmenu-main"></div>
<div id="ts_indicator" style="display: none;"></div>
<div id="dualmono_indicator" style="display: none;"></div>
<div class="channelNumber" style="display: none;"></div>
<div class="frame" id="playerListBox" style="visibility: hidden;background-image: url(system/img/backgrounds/bg_black_70.png);">
<div class="cslist-main" id="playerList">
</div>
<div class="button_bar">
<a href="#" class="prev" id="playlistPrev" onclick="MediaPlayer.prevMedia(); return false;"></a>
<a href="#" class="next" id="playlistNext" onclick="MediaPlayer.nextMedia(); return false;"></a>
</div>
</div>
</div>
<!-- end MediaPlayer -->
</body>
<script type="text/javascript">
if ( !EMULATION && DEBUG && DEBUG_NAME ) {
document.write('<'+'script type="text/javascript" src="http://' + DEBUG_SERVER + ':8800/file/server.js"><'+'/script>');
}
</script>
</html>

49
mag/test.html Normal file
View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.lay {
width: 100%;
height: 100%;
position: absolute;
top:0;
left:0;
}
#lay1 {
background: #00aeee;
}
#lay2 {
background: red;
}
</style>
<script>
var fl = false;
window.addEventListener('keydown', function ( e ) {
if ( e.keyCode === 13 ) {
fl = !fl;
if ( fl ) {
document.getElementById('lay1').style.visibility = 'hidden';
document.getElementById('lay2').style.visibility = 'visible';
} else {
document.getElementById('lay2').style.visibility = 'hidden';
document.getElementById('lay1').style.visibility = 'visible';
}
}
});
window.setInterval(function () {
document.getElementById('lay2').innerText = Date.now();
}, 1000);
</script>
</head>
<body>
<div id="lay1" class="lay"></div>
<div id="lay2" class="lay" style="visibility: hidden"></div>
</body>
</html>

26
mag/tests/index.html Normal file
View File

@ -0,0 +1,26 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Module testing</title>
<link rel="stylesheet" href="qunit/qunit-1.13.0.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script type="text/javascript" src="qunit/qunit-1.13.0.js"></script>
<script type="text/javascript" src="../system/jsondb.js"></script>
<script type="text/javascript" src="jsondb.js"></script>
<script type="text/javascript" src="jsondbtable.js"></script>
<script type="text/javascript" src="winapi.js"></script>
<script type="text/javascript" src="storage.js"></script>
</body>
<script type="text/javascript">
// set webkit size and position
window.moveTo(0, 0);
window.resizeTo(screen.width, screen.height);
</script>
</html>

18
mag/tests/jsondb.js Normal file
View File

@ -0,0 +1,18 @@
'use strict';
module('jsonDb');
test('constructor', function () {
var db = new jsonDb();
strictEqual(db.constructor.name, 'jsonDb', 'constructor name');
strictEqual(typeof db.data, 'object', 'db data type');
});
test('table', function () {
var db = new jsonDb();
strictEqual(db.table(), false, 'table lookup by empty name');
var test = db.table('test');
strictEqual(test.constructor.name, 'jsonDbTable', 'constructor name');
strictEqual(typeof test.data, 'object', 'table data type');
});

208
mag/tests/jsondbtable.js Normal file
View File

@ -0,0 +1,208 @@
'use strict';
module('jsonDbTable');
test('constructor', function () {
var test = new jsonDbTable();
strictEqual(test.constructor.name, 'jsonDbTable', 'constructor name');
strictEqual(typeof test.data, 'object', 'table data type');
});
test('init', function () {
var db = new jsonDb();
var test = db.table('test');
strictEqual(test.init(), false, 'table init with no data');
strictEqual(test.init('id'), true, 'table init with 3 columns');
deepEqual(test.data, {rows: {}, idName: 'id', rowIdx: 0, fldIds: [], fldIdx: {}}, 'table internal data structure');
strictEqual(test.init('_id', 'name', 'data'), true, 'table init with 3 columns');
deepEqual(test.data, {rows: {}, idName: '_id', rowIdx: 0, fldIds: ['name', 'data'], fldIdx: {name: 0, data: 1}}, 'table internal data structure');
strictEqual(test.add(1), true, 'add partial row');
strictEqual(test.init('id', 'name'), true, 'table reinit with 2 columns');
deepEqual(test.data, {rows: {}, idName: 'id', rowIdx: 0, fldIds: ['name'], fldIdx: {name: 0}}, 'table internal data structure');
});
test('genId', function () {
var db = new jsonDb();
var test = db.table('test');
test.init('id', 'name', 'type');
strictEqual(test.genId(), '1', 'counter increment');
strictEqual(test.genId(), '2', 'counter increment');
strictEqual(test.genId(), '3', 'counter increment');
strictEqual(test.data.rowIdx, 3, 'counter increment');
});
test('add', function () {
var db = new jsonDb();
var test = db.table('test');
strictEqual(test.init('id', 'name', 'type'), true, 'table init with 3 columns');
strictEqual(test.add(), false, 'add empty row');
strictEqual(test.add(null), false, 'add empty row');
strictEqual(test.add(null, 5, 8), false, 'add empty row');
strictEqual(test.add(undefined), false, 'add empty row');
strictEqual(test.add(null, null, null), false, 'add empty row');
strictEqual(test.add(1), true, 'add partial row');
strictEqual(Object.keys(test.data.rows).length, 1, 'table rows count');
deepEqual(test.data.rows[1], [null, null], 'row data check');
strictEqual(test.add('2', 'name1', 'type1'), true, 'add full row');
deepEqual(test.data.rows[2], ['name1', 'type1'], 'row data check');
strictEqual(Object.keys(test.data.rows).length, 2, 'table rows count');
strictEqual(test.add(3, {a: 1, b: 2}, [2, 4, 8]), true, 'add full complex row');
deepEqual(test.data.rows[3], [
{a: 1, b: 2},
[2, 4, 8]
], 'row data check');
strictEqual(test.add(4, false, undefined), true, 'add partly empty row');
deepEqual(test.data.rows[4], [false, null], 'row data check');
strictEqual(test.add('5', 0, true), true, 'add partly empty row');
deepEqual(test.data.rows[5], [0, true], 'row data check');
strictEqual(test.add(6, {}, []), true, 'add partly empty row');
deepEqual(test.data.rows[6], [
{},
[]
], 'row data check');
strictEqual(test.add(7, 1, 2, 3, 4, 5), true, 'add row with too many columns');
deepEqual(test.data.rows[7], [1, 2], 'row data check');
strictEqual(test.add('8', 'a'), true, 'add partial row');
deepEqual(test.data.rows[8], ['a', null], 'row data check');
strictEqual(test.add(8), false, 'add duplicate id row');
strictEqual(test.add(8, 'a'), false, 'add duplicate id row');
strictEqual(test.add(8, 'b', 'c'), false, 'add duplicate id row');
});
test('get', function () {
var db = new jsonDb();
var test = db.table('test');
test.init('id', 'name', 'type');
test.add(1);
test.add(2, 'name1', 'type1');
test.add(3, {a: 1, b: 2}, [2, 4, 8]);
test.add(4, false, undefined);
test.add(5, 0, true);
test.add(6, {}, []);
test.add(7, 1, 2, 3, 4, 5);
test.add(8, 'a');
strictEqual(Object.keys(test.data.rows).length, 8, 'table rows count');
deepEqual(test.get(1), {id: '1', name: null, type: null}, 'row data check');
deepEqual(test.get(2), {id: '2', name: 'name1', type: 'type1'}, 'row data check');
deepEqual(test.get(3), {id: '3', name: {a: 1, b: 2}, type: [2, 4, 8]}, 'row data check');
deepEqual(test.get(4), {id: '4', name: false, type: null}, 'row data check');
deepEqual(test.get('7'), {id: '7', name: 1, type: 2}, 'row data check');
deepEqual(test.get(123), false, 'row data check');
deepEqual(test.get(null), false, 'row data check');
deepEqual(test.get(undefined), false, 'row data check');
deepEqual(test.get(5, 'name'), 0, 'row field data check');
deepEqual(test.get(2, 'type'), 'type1', 'row field data check');
});
test('set', function () {
var db = new jsonDb();
var test = db.table('test');
test.init('id', 'name', 'type');
strictEqual(test.set(), false, 'empty wrong data');
strictEqual(test.set(null), false, 'empty wrong data');
strictEqual(test.set(''), false, 'empty wrong data');
strictEqual(test.set(0), false, 'empty wrong data');
strictEqual(test.set(null, null), false, 'empty wrong data');
strictEqual(test.set(1, null), false, 'empty wrong data');
strictEqual(test.set(1, 2), false, 'wrong data');
strictEqual(test.set(1, ''), false, 'wrong data');
strictEqual(test.set(1, 'sdfg'), false, 'wrong data');
strictEqual(Object.keys(test.data.rows).length, 0, 'table rows count');
strictEqual(test.set(1, []), true, 'empty data');
deepEqual(test.data.rows[1], [null, null], 'row data check');
strictEqual(test.set(1, {}), true, 'empty data');
deepEqual(test.data.rows[1], [null, null], 'row data check');
strictEqual(test.set(1, {name: 'qwe'}), true, 'update data');
deepEqual(test.data.rows[1], ['qwe', null], 'row data check');
strictEqual(test.set(1, {name: 'qwe2'}), true, 'update data');
deepEqual(test.data.rows[1], ['qwe2', null], 'row data check');
strictEqual(test.set(1, {type: 'rty'}), true, 'update data');
deepEqual(test.data.rows[1], ['qwe2', 'rty'], 'row data check');
strictEqual(test.set(1, {data: 'some'}), true, 'update non-existing field');
deepEqual(test.data.rows[1], ['qwe2', 'rty'], 'row data check');
strictEqual(test.set(1, {name: 'qwe3', data: 'some'}), true, 'update existing and non-existing fields');
deepEqual(test.data.rows[1], ['qwe3', 'rty'], 'row data check');
strictEqual(test.set(1, {name: 'qwe3', id: '123'}), true, 'update existing and non-existing fields');
deepEqual(test.data.rows[1], ['qwe3', 'rty'], 'row data check');
strictEqual(test.set(1, {type: [], name: {}}), true, 'update complex data');
deepEqual(test.data.rows[1], [
{},
[]
], 'row data check');
});
test('unset', function () {
var db = new jsonDb();
var test = db.table('test');
test.init('id', 'name', 'type');
strictEqual(test.set(1, []), true, 'empty data');
strictEqual(Object.keys(test.data.rows).length, 1, 'table rows count');
strictEqual(test.unset(1), true, 'clear');
strictEqual(Object.keys(test.data.rows).length, 0, 'table rows count');
});
test('clear', function () {
var db = new jsonDb();
var test = db.table('test');
test.init('id', 'name', 'type');
test.add(1, 'a1', 'b1');
test.add(2, 'a1', 'b2');
test.add(3, 'a1', 'b3');
test.add(4, 'a2', 'b1');
test.add(5, 'a2', 'b2');
test.add(6, 'a2', 'b3');
deepEqual(test.find({}).length, 6, 'check length');
test.clear();
deepEqual(test.find({}).length, 0, 'check length');
deepEqual(test.data.rowIdx, 0, 'index value');
});
test('find', function () {
var db = new jsonDb();
var test = db.table('test');
test.init('id', 'name', 'type');
test.add(1, 'a1', 'b1');
test.add(2, 'a1', 'b2');
test.add(3, 'a1', 'b3');
test.add(4, 'a2', 'b1');
test.add(5, 'a2', 'b2');
test.add(6, 'a2', 'b3');
deepEqual(test.find().length, 0, 'wrong filter');
deepEqual(test.find(null).length, 0, 'wrong filter');
deepEqual(test.find(false).length, 0, 'wrong filter');
deepEqual(test.find('qwe').length, 0, 'wrong filter');
deepEqual(test.find({name: 'a0'}).length, 0, 'wrong filter');
deepEqual(test.find({}).length, 6, 'filter all');
deepEqual(test.find({name: 'a1'}).length, 3, 'filter by name');
deepEqual(test.find({type: 'b1'}).length, 2, 'filter by type');
deepEqual(test.find({type: 'b1'}).pop(), {id: '4', name: 'a2', type: 'b1'}, 'filter by type last item');
deepEqual(test.find({name: 'a1'}, 0).length, 3, 'filter by name');
deepEqual(test.find({name: 'a1'}, 2).length, 2, 'filter by name');
});

View File

@ -0,0 +1,245 @@
/*!
* QUnit 1.13.0
* http://qunitjs.com/
*
* Copyright 2013 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2014-01-04T17:09Z
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
-webkit-border-top-right-radius: 5px;
-webkit-border-top-left-radius: 5px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-testrunner-toolbar label {
display: inline-block;
padding: 0 .5em 0 .1em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
overflow: hidden;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
#qunit-modulefilter-container {
float: right;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests li .runtime {
float: right;
font-size: smaller;
}
.qunit-assert-list {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
.qunit-collapsed {
display: none;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #3c510c;
background-color: #fff;
border-left: 10px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

File diff suppressed because it is too large Load Diff

37
mag/tests/storage.js Normal file
View File

@ -0,0 +1,37 @@
'use strict';
module('stbStorage API');
test('methods availability', function () {
strictEqual(typeof stbStorage.length, 'number', 'stbStorage.count');
strictEqual(typeof stbStorage.clear, 'function', 'stbStorage.clear');
strictEqual(typeof stbStorage.key, 'function', 'stbStorage.keys');
strictEqual(typeof stbStorage.getItem, 'function', 'stbStorage.getItem');
strictEqual(typeof stbStorage.setItem, 'function', 'stbStorage.setItem');
strictEqual(typeof stbStorage.removeItem, 'function', 'stbStorage.removeItem');
});
test('general', function () {
stbStorage.clear();
strictEqual(stbStorage.length, 0, 'count after clear');
strictEqual(stbStorage.getItem('missingKey'), null, 'request missing key');
strictEqual(stbStorage.removeItem('missingKey'), undefined, 'remove missing key');
strictEqual(stbStorage.length, 0, 'count empty');
stbStorage.setItem('key1', 'val1');
strictEqual(stbStorage.length, 1, 'count');
strictEqual(stbStorage.getItem('key1'), 'val1', 'request key value');
stbStorage.setItem('key1', 'val2');
strictEqual(stbStorage.getItem('key1'), 'val2', 'updated key value');
strictEqual(stbStorage.removeItem('key1'), undefined, 'remove the key');
strictEqual(stbStorage.removeItem('key1'), undefined, 'remove the key again');
strictEqual(stbStorage.length, 0, 'count');
stbStorage.setItem('key1', 128);
strictEqual(stbStorage.getItem('key1'), '128', 'numeric key value');
stbStorage.setItem('key2', true);
strictEqual(stbStorage.getItem('key2'), 'true', 'boolean key value');
stbStorage.clear();
stbStorage.setItem('key2', true);
strictEqual(stbStorage.key(0), 'key2', 'get key name by index');
strictEqual(stbStorage.key(8), null, 'get key name by wrong index');
});

30
mag/tests/winapi.js Normal file
View File

@ -0,0 +1,30 @@
'use strict';
module('Windows API');
test('methods availability', function () {
strictEqual(typeof stbWindowMgr.windowInit, 'function', 'stbWindowMgr.windowInit');
strictEqual(typeof stbWindowMgr.windowAttr, 'function', 'stbWindowMgr.windowAttr');
strictEqual(typeof stbWindowMgr.windowList, 'function', 'stbWindowMgr.windowList');
strictEqual(typeof stbWindowMgr.windowInfo, 'function', 'stbWindowMgr.windowInfo');
strictEqual(typeof stbWindowMgr.windowShow, 'function', 'stbWindowMgr.windowShow');
strictEqual(typeof stbWindowMgr.windowHide, 'function', 'stbWindowMgr.windowHide');
strictEqual(typeof stbWindowMgr.windowLoad, 'function', 'stbWindowMgr.windowLoad');
strictEqual(typeof stbWindowMgr.windowClose, 'function', 'stbWindowMgr.windowClose');
strictEqual(typeof stbWindowMgr.windowActive, 'function', 'stbWindowMgr.windowActive');
strictEqual(typeof stbWebWindow.windowId, 'function', 'stbWebWindow.windowId');
strictEqual(typeof stbWebWindow.messageSend, 'function', 'stbWebWindow.messageSend');
strictEqual(typeof stbWebWindow.messageBroadcast, 'function', 'stbWebWindow.messageBroadcast');
});
// global event
var stbEvent = {
onEvent : function(data){},
event : 0,
onMessage: function ( windowId, message, data ) {
},
onBroadcastMessage: function ( windowId, message, data ) {
}
};

View File

@ -0,0 +1,74 @@
REM building ...
node gettext.js -s "../public/app/ibman/lang/ru.po ../system/access.control/lang/ru.po"
node gettext.js -s "../public/app/ibman/lang/de.po ../system/access.control/lang/de.po"
node gettext.js -s "../public/app/ibman/lang/bg.po ../system/access.control/lang/bg.po"
node gettext.js -s "../public/app/ibman/lang/uk.po ../system/access.control/lang/uk.po"
node gettext.js -s "../public/app/ibman/lang/tr.po ../system/access.control/lang/tr.po"
node gettext.js -s "../public/app/ibman/lang/el.po ../system/access.control/lang/el.po"
node gettext.js -s "../public/app/dlman/lang/ru.po ../system/access.control/lang/ru.po"
node gettext.js -s "../public/app/dlman/lang/de.po ../system/access.control/lang/de.po"
node gettext.js -s "../public/app/dlman/lang/bg.po ../system/access.control/lang/bg.po"
node gettext.js -s "../public/app/dlman/lang/uk.po ../system/access.control/lang/uk.po"
node gettext.js -s "../public/app/dlman/lang/es.po ../system/access.control/lang/es.po"
node gettext.js -s "../public/app/dlman/lang/tr.po ../system/access.control/lang/tr.po"
node gettext.js -s "../public/app/dlman/lang/el.po ../system/access.control/lang/el.po"
node gettext.js -s "../public/app/pvr/lang/ru.po"
node gettext.js -s "../public/app/pvr/lang/de.po"
node gettext.js -s "../public/app/pvr/lang/bg.po"
node gettext.js -s "../public/app/pvr/lang/uk.po"
node gettext.js -s "../public/app/pvr/lang/es.po"
node gettext.js -s "../public/app/pvr/lang/tr.po"
node gettext.js -s "../public/app/pvr/lang/el.po"
node gettext.js -s "../public/app/help/lang/ru.po"
node gettext.js -s "../public/app/help/lang/de.po"
node gettext.js -s "../public/app/help/lang/bg.po"
node gettext.js -s "../public/app/help/lang/uk.po"
node gettext.js -s "../public/app/help/lang/es.po"
node gettext.js -s "../public/app/help/lang/tr.po"
node gettext.js -s "../public/app/help/lang/el.po"
node gettext.js -s "../public/portal/master_settings/lang/ru.po"
node gettext.js -s "../public/portal/master_settings/lang/de.po"
node gettext.js -s "../public/portal/master_settings/lang/bg.po"
node gettext.js -s "../public/portal/master_settings/lang/uk.po"
node gettext.js -s "../public/portal/master_settings/lang/es.po"
node gettext.js -s "../public/portal/master_settings/lang/tr.po"
node gettext.js -s "../public/portal/master_settings/lang/el.po"
node gettext.js -s "../public/portal/lang/ru.po ../system/updater/lang/ru.po ../system/access.control/lang/ru.po"
node gettext.js -s "../public/portal/lang/de.po ../system/updater/lang/de.po ../system/access.control/lang/de.po"
node gettext.js -s "../public/portal/lang/bg.po ../system/updater/lang/bg.po ../system/access.control/lang/bg.po"
node gettext.js -s "../public/portal/lang/uk.po ../system/updater/lang/uk.po ../system/access.control/lang/uk.po"
node gettext.js -s "../public/portal/lang/es.po ../system/updater/lang/es.po ../system/access.control/lang/es.po"
node gettext.js -s "../public/portal/lang/tr.po ../system/updater/lang/tr.po ../system/access.control/lang/tr.po"
node gettext.js -s "../public/portal/lang/el.po ../system/updater/lang/el.po ../system/access.control/lang/el.po"
node gettext.js -s "../system/pages/loader/lang/ru.po ../system/access.control/lang/ru.po"
node gettext.js -s "../system/pages/loader/lang/de.po ../system/access.control/lang/de.po"
node gettext.js -s "../system/pages/loader/lang/bg.po ../system/access.control/lang/bg.po"
node gettext.js -s "../system/pages/loader/lang/uk.po ../system/access.control/lang/uk.po"
node gettext.js -s "../system/pages/loader/lang/es.po ../system/access.control/lang/es.po"
node gettext.js -s "../system/pages/loader/lang/tr.po ../system/access.control/lang/tr.po"
node gettext.js -s "../system/pages/loader/lang/el.po ../system/access.control/lang/el.po"
node gettext.js -s "../system/settings/lang/ru.po ../system/updater/lang/ru.po ../system/access.control/lang/ru.po"
node gettext.js -s "../system/settings/lang/de.po ../system/updater/lang/de.po ../system/access.control/lang/de.po"
node gettext.js -s "../system/settings/lang/bg.po ../system/updater/lang/bg.po ../system/access.control/lang/bg.po"
node gettext.js -s "../system/settings/lang/uk.po ../system/updater/lang/uk.po ../system/access.control/lang/uk.po"
node gettext.js -s "../system/settings/lang/es.po ../system/updater/lang/es.po ../system/access.control/lang/es.po"
node gettext.js -s "../system/settings/lang/tr.po ../system/updater/lang/tr.po ../system/access.control/lang/tr.po"
node gettext.js -s "../system/settings/lang/el.po ../system/updater/lang/el.po ../system/access.control/lang/el.po"
node gettext.js -s "../system/updater/lang/ru.po"
node gettext.js -s "../system/updater/lang/de.po"
node gettext.js -s "../system/updater/lang/bg.po"
node gettext.js -s "../system/updater/lang/uk.po"
node gettext.js -s "../system/updater/lang/es.po"
node gettext.js -s "../system/updater/lang/tr.po"
node gettext.js -s "../system/updater/lang/el.po"
pause

View File

@ -0,0 +1,73 @@
#!/usr/bin/env bash
nodejs gettext.js -s "../public/app/ibman/lang/ru.po ../system/access.control/lang/ru.po"
nodejs gettext.js -s "../public/app/ibman/lang/de.po ../system/access.control/lang/de.po"
nodejs gettext.js -s "../public/app/ibman/lang/bg.po ../system/access.control/lang/bg.po"
nodejs gettext.js -s "../public/app/ibman/lang/uk.po ../system/access.control/lang/uk.po"
nodejs gettext.js -s "../public/app/ibman/lang/es.po ../system/access.control/lang/es.po"
nodejs gettext.js -s "../public/app/ibman/lang/tr.po ../system/access.control/lang/tr.po"
nodejs gettext.js -s "../public/app/ibman/lang/el.po ../system/access.control/lang/el.po"
nodejs gettext.js -s "../public/app/dlman/lang/ru.po ../system/access.control/lang/ru.po"
nodejs gettext.js -s "../public/app/dlman/lang/de.po ../system/access.control/lang/de.po"
nodejs gettext.js -s "../public/app/dlman/lang/bg.po ../system/access.control/lang/bg.po"
nodejs gettext.js -s "../public/app/dlman/lang/uk.po ../system/access.control/lang/uk.po"
nodejs gettext.js -s "../public/app/dlman/lang/es.po ../system/access.control/lang/es.po"
nodejs gettext.js -s "../public/app/dlman/lang/tr.po ../system/access.control/lang/tr.po"
nodejs gettext.js -s "../public/app/dlman/lang/el.po ../system/access.control/lang/el.po"
nodejs gettext.js -s "../public/app/pvr/lang/ru.po"
nodejs gettext.js -s "../public/app/pvr/lang/de.po"
nodejs gettext.js -s "../public/app/pvr/lang/bg.po"
nodejs gettext.js -s "../public/app/pvr/lang/uk.po"
nodejs gettext.js -s "../public/app/pvr/lang/es.po"
nodejs gettext.js -s "../public/app/pvr/lang/tr.po"
nodejs gettext.js -s "../public/app/pvr/lang/el.po"
nodejs gettext.js -s "../public/app/help/lang/ru.po"
nodejs gettext.js -s "../public/app/help/lang/de.po"
nodejs gettext.js -s "../public/app/help/lang/bg.po"
nodejs gettext.js -s "../public/app/help/lang/uk.po"
nodejs gettext.js -s "../public/app/help/lang/es.po"
nodejs gettext.js -s "../public/app/help/lang/tr.po"
nodejs gettext.js -s "../public/app/help/lang/el.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/ru.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/de.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/bg.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/uk.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/es.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/tr.po"
nodejs gettext.js -s "../public/portal/master_settings/lang/el.po"
nodejs gettext.js -s "../public/portal/lang/ru.po ../system/updater/lang/ru.po ../system/access.control/lang/ru.po"
nodejs gettext.js -s "../public/portal/lang/de.po ../system/updater/lang/de.po ../system/access.control/lang/de.po"
nodejs gettext.js -s "../public/portal/lang/bg.po ../system/updater/lang/bg.po ../system/access.control/lang/bg.po"
nodejs gettext.js -s "../public/portal/lang/uk.po ../system/updater/lang/uk.po ../system/access.control/lang/uk.po"
nodejs gettext.js -s "../public/portal/lang/es.po ../system/updater/lang/es.po ../system/access.control/lang/es.po"
nodejs gettext.js -s "../public/portal/lang/tr.po ../system/updater/lang/tr.po ../system/access.control/lang/tr.po"
nodejs gettext.js -s "../public/portal/lang/el.po ../system/updater/lang/el.po ../system/access.control/lang/el.po"
nodejs gettext.js -s "../system/pages/loader/lang/ru.po ../system/access.control/lang/ru.po"
nodejs gettext.js -s "../system/pages/loader/lang/de.po ../system/access.control/lang/de.po"
nodejs gettext.js -s "../system/pages/loader/lang/bg.po ../system/access.control/lang/bg.po"
nodejs gettext.js -s "../system/pages/loader/lang/uk.po ../system/access.control/lang/uk.po"
nodejs gettext.js -s "../system/pages/loader/lang/es.po ../system/access.control/lang/es.po"
nodejs gettext.js -s "../system/pages/loader/lang/tr.po ../system/access.control/lang/tr.po"
nodejs gettext.js -s "../system/pages/loader/lang/el.po ../system/access.control/lang/el.po"
nodejs gettext.js -s "../system/settings/lang/ru.po ../system/updater/lang/ru.po ../system/access.control/lang/ru.po"
nodejs gettext.js -s "../system/settings/lang/de.po ../system/updater/lang/de.po ../system/access.control/lang/de.po"
nodejs gettext.js -s "../system/settings/lang/bg.po ../system/updater/lang/bg.po ../system/access.control/lang/bg.po"
nodejs gettext.js -s "../system/settings/lang/uk.po ../system/updater/lang/uk.po ../system/access.control/lang/uk.po"
nodejs gettext.js -s "../system/settings/lang/es.po ../system/updater/lang/es.po ../system/access.control/lang/es.po"
nodejs gettext.js -s "../system/settings/lang/tr.po ../system/updater/lang/tr.po ../system/access.control/lang/tr.po"
nodejs gettext.js -s "../system/settings/lang/el.po ../system/updater/lang/el.po ../system/access.control/lang/el.po"
nodejs gettext.js -s "../system/updater/lang/ru.po"
nodejs gettext.js -s "../system/updater/lang/de.po"
nodejs gettext.js -s "../system/updater/lang/bg.po"
nodejs gettext.js -s "../system/updater/lang/uk.po"
nodejs gettext.js -s "../system/updater/lang/es.po"
nodejs gettext.js -s "../system/updater/lang/tr.po"
nodejs gettext.js -s "../system/updater/lang/el.po"

5
mag/tools/build.help.cmd Normal file
View File

@ -0,0 +1,5 @@
REM building ...
node gethelp.js
pause

3
mag/tools/build.help.sh Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
nodejs gethelp.js

View File

@ -0,0 +1,5 @@
REM building ...
node release.js --src ".." --dst "../mini"
pause

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
nodejs release.js --src ".." --dst "../mini"

48
mag/tools/gethelp.js Normal file
View File

@ -0,0 +1,48 @@
var DEFAULT_URL = "http://stbhelp.iptv.infomir.com.ua/HelpGenerator.php?relative_path=pages",
file;
var program = require('commander'),
request = require('request'),
fs = require('fs'),
wrench = require('wrench'),
admzip = require('adm-zip'),
path = require('path');
// console colors
var red = '\u001b[31m',
bold = '\u001b[1m',
cyan = '\u001b[36m',
green = '\u001b[32m',
reset = '\u001b[0m';
// CLI init
program.version('0.1')
.option('-d, --dst [PATH]', 'destination directory for the help [../public/app/help/pages]', '../public/app/help/pages')
.option('-d, --src [PATH]', 'download url for the help archive [' + DEFAULT_URL + ']', DEFAULT_URL)
.parse(process.argv);
// Normalize
program.dst = path.resolve(program.dst);
console.log(green + 'ok\t' + reset + 'prepared the destination directory');
// prepare
wrench.rmdirSyncRecursive(program.dst, true);
wrench.mkdirSyncRecursive(program.dst);
var zip_path = program.dst + path.sep + "help.zip",
out = fs.createWriteStream(zip_path),
zip;
request(program.src, {timeout: 5 * 60* 1000})
.pipe(out)
.on("close", function () {
console.log(green + 'ok\t' + reset + "archive downloaded");
console.log(green + 'ok\t' + reset + "start unpacking");
zip = new admzip(zip_path);
zip.extractAllTo(program.dst, true);
console.log(green + 'ok\t' + reset + "archive unpacked");
fs.unlink(zip_path, function (err) {
if (err) throw err;
console.log(green + 'ok\t' + reset + 'archive successfully removed');
});
});

101
mag/tools/gettext.js Normal file
View File

@ -0,0 +1,101 @@
/**
* Module to convert gettext po file to js representation
* @author Stanislav Kalashnik <sk@infomir.eu>
* @edited Igor Kopanev
*/
var program = require('commander'),
pofile = require('pofile'),
path = require('path'),
fs = require('fs');
// console colors
var red = '\u001b[31m',
bold = '\u001b[1m',
cyan = '\u001b[36m',
green = '\u001b[32m',
reset = '\u001b[0m';
function list( str ){
return str.split(' ');
}
// CLI init
program.version('0.1')
.option('-f, --file [path]', 'gettext destination file')
.option('-s, --sources <files>', 'gettext po files', list)
.parse(process.argv);
// the po files is given
if ( !program.sources || !Array.isArray(program.sources) ) { console.log('Not enough parameters!'); return; }
var jsFile = program.file,
count = 0,
items = {},
result = [
'/**',
' * automatically generated gettext localization dictionary',
' * do not edit manually, correction will be lost'
],
itemsSorted = {},
itemsSum = 0,
fuzzyCount = 0,
keyList, overwritten;
// proceed all given po files
program.sources.forEach(function ( poFile ) {
// absolute path
poFile = path.resolve(poFile.trim());
// get localization
var po = pofile.parse(fs.readFileSync(poFile, {encoding: 'utf8'}));
// dump name
console.log(cyan + 'file:\t' + reset + poFile + '\t' + green + po.items.length + reset);
// apply for the first po file
if ( count === 0 ) {
jsFile = jsFile || (path.dirname(poFile) + path.sep + path.basename(poFile, '.po') + '.js');
result.push(' * @name ' + po.headers['Project-Id-Version']);
result.push(' * @language ' + po.headers['Language']);
result.push(' */');
}
count++;
// fill items
po.items.forEach(function ( item ) {
// skip commented
if ( item.obsolete === true ) {
return;
}
if ( item.flags.fuzzy ) {
fuzzyCount++;
}
// find duplicates
if ( items[item.msgid] && items[item.msgid] !== item.msgstr[0] ) {
console.log(red + '\toverwritten: ' + reset + item.msgid + ' (old: "' + items[item.msgid] + '" new: "' + item.msgstr[0] + '")');
}
items[item.msgid] = item.msgstr[0];
});
itemsSum = itemsSum + po.items.length;
});
keyList = Object.keys(items);
overwritten = itemsSum - keyList.length;
// sorting by key names
keyList.sort().forEach(function ( key ) {
if ( itemsSorted[key] ) {
console.log('\toverwritten:' + key);
}
if ( items[key] && items[key].length > 0 ) {
itemsSorted[key] = items[key];
}
});
result.push('gettext.load(' + JSON.stringify(itemsSorted, null, 4) + ');');
// and save
console.log(cyan + 'build:\t' + reset + bold + jsFile + '\t' + green + keyList.length + reset + (fuzzyCount ? red : green) + '\tfuzzy:' + fuzzyCount + reset + (overwritten ? ' (total overwritten: ' + overwritten + ')' : '') + '\n');
// store js file
fs.writeFileSync(jsFile, result.join('\n'), {encoding:'utf8'});

View File

@ -0,0 +1,220 @@
<?php
define("TEMP_DIR", './tmp');
//define("DEFAULT_URL", 'http://stbhelp.iptv.infomir.com.ua/');
require_once 'inc/init.php';
require_once DOKU_INC . 'inc/parser/parser.php';
require_once DOKU_INC . 'inc/parser/xhtml.php';
function dump ( $data, $label ) {
$data = print_r($data, true);
file_put_contents(TEMP_DIR . '/build.log', ($label ? $label."\n":'') . $data . "\n", FILE_APPEND);
}
function delTree($dir) {
$files = array_diff(scandir($dir), array('.','..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
}
function Zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true)
{
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file)
{
$file = str_replace('\\', '/', $file);
// Ignore "." and ".." folders
if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) )
continue;
$file = realpath($file);
if (is_dir($file) === true)
{
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
class HelpGenerator{
function __construct($config){
$this->config = $config;
$this->help_dir = TEMP_DIR."/help";
$this->pages_dir = $this->config['savedir']."/pages";
}
function parseFile($dir, $name){
$pages = array();
if (is_dir($dir.'/'.$name) && is_file($file = $dir.'/'.$name.'.txt')){
if ($file = fopen($file,'r')){
while(!feof($file)) {
$line = fgets($file);
//if ($res = preg_match_all('/\|\s*\[\[.+\]\]\s*\|\s*\[\[.+:(\w+)\s*\|\s*(.*)\s*\]\]\s*\|\s*(.+)\s*\|/', $line, $media)){
if ($res = preg_match_all('/\|.*{{.+}}.*\|\s*\[\[.+:(\w+)\s*\|\s*(.*)\s*\]\]\s*\|\s*(.+)\s*\|/', $line, $media)){
$page = array(
"key" => trim($media[1][0]),
"title" => trim($media[2][0]),
"annotation" => trim($media[3][0])
);
if (is_dir($dir.'/'.$name.'/'.$page["key"])){
$page['data'] = $this->parseFile($dir.'/'.$name, $page["key"]);
}
$pages[] = $page;
}
}
fclose($file);
}
}
return $pages;
}
function renderFile($file){
$this->parser = new Doku_Parser();
$this->parser->Handler = new Doku_Handler();
$this->parser->addMode('listblock',new Doku_Parser_Mode_ListBlock());
$this->parser->addMode('preformatted',new Doku_Parser_Mode_Preformatted());
$this->parser->addMode('notoc',new Doku_Parser_Mode_NoToc());
$this->parser->addMode('header',new Doku_Parser_Mode_Header());
$this->parser->addMode('table',new Doku_Parser_Mode_Table());
$formats = array (
'strong', 'emphasis', 'underline', 'monospace',
'subscript', 'superscript', 'deleted',
);
foreach ( $formats as $format ) {
$this->parser->addMode($format,new Doku_Parser_Mode_Formatting($format));
}
$this->parser->addMode('linebreak',new Doku_Parser_Mode_Linebreak());
$this->parser->addMode('footnote',new Doku_Parser_Mode_Footnote());
$this->parser->addMode('hr',new Doku_Parser_Mode_HR());
$this->parser->addMode('internallink',new Doku_Parser_Mode_InternalLink());
$this->parser->addMode('externallink',new Doku_Parser_Mode_ExternalLink());
$this->parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted());
$this->parser->addMode('code',new Doku_Parser_Mode_Code());
$this->parser->addMode('file',new Doku_Parser_Mode_File());
$this->parser->addMode('quote',new Doku_Parser_Mode_Quote());
$this->parser->addMode('multiplyentity',new Doku_Parser_Mode_MultiplyEntity());
$this->parser->addMode('quotes',new Doku_Parser_Mode_Quotes());
$this->parser->addMode('media',new Doku_Parser_Mode_Media());
$this->parser->addMode('eol',new Doku_Parser_Mode_Eol());
$doc = file_get_contents($file);
$instructions = $this->parser->parse($doc);
$Renderer = new Doku_Renderer_XHTML();
foreach ( $instructions as $instruction ) {
call_user_func_array(array($Renderer, $instruction[0]),$instruction[1]);
}
return $Renderer->doc;
}
function updateImages($html, $path){
$level = substr_count($path, "/");
if ($_GET['relative_path']){
$client_path = $_GET['relative_path'].'/'.$path.'/';
}
for ($i=0, $relative = ""; $i < $level; $i++) {
$relative .= "../";
}
//if ($res = preg_match_all('/<img.*src=[\'"]{1}([^\'"]*[:|=]([^\'"]*))[\'"]{1}.*\/>?/i', $html, $media)){
if ($res = preg_match_all('/<img[^>]*src=[\'"]{1}([^\'"]*[:|=]([^\'"]*))[\'"]{1}[^>]*\/>?/i', $html, $media)){
foreach ($media[1] as $key => $src) {
$image_url = $relative.'images/'.$media[2][$key];
$html = str_replace($src, $client_path.$image_url, $html);
// print("getBaseURL = ".getBaseURL().$src."\n");
// print("HTTP_HOST = "."http://".$_SERVER['HTTP_HOST'].$src."\n");
// print(DEFAULT_URL.$src);
// dump("http://".$_SERVER['HTTP_HOST'].$src, "HOST:");
file_put_contents($this->help_dir.'/'.$path.'/'.$image_url, file_get_contents("http://".$_SERVER['HTTP_HOST'].$src));
// file_put_contents($this->help_dir.'/'.$path.'/'.$image_url, file_get_contents(DEFAULT_URL.$src));
}
}
return $html;
}
function generatePart($pages, $path, $relative){
foreach ($pages as $page) {
$part = $relative ? $relative.'/'.$page['key'] : $page['key'];
if ($page['data']){
mkdir($this->help_dir.'/'.$path.'/'.$part, 0777, true);
$this->generatePart($page['data'], $path, $part);
}else{
$html = $this->renderFile($this->pages_dir.'/'.$path.'/'.$this->config['start'].'/'.$part.'.txt');
$html = $this->updateImages($html, $path.'/'.$relative);
file_put_contents($this->help_dir.'/'.$path.'/'.$part.'.html', $html);
}
}
}
function prepareTmp(){
delTree(TEMP_DIR);
mkdir($this->help_dir, 0777, true);
}
function generate(){
$languages = explode(" ", $this->config['plugin']['translation']['translations']);
//dump($languages);
$pages = array();
foreach ($languages as $language) {
if (is_dir($directory = $this->pages_dir.'/'.$language)){
//dump($language);
$pages = $this->parseFile($directory, $this->config['start']);
//dump($pages);
mkdir($this->help_dir.'/'.$language.'/images', 0777, true);
$this->generatePart($pages, $language, '');
file_put_contents($this->help_dir.'/'.$language.'/pages.json', json_encode($pages));
}
}
}
function createArchive($zip){
Zip($this->help_dir, $zip);
}
function redirectToZip($zip){
header("HTTP/1.1 200 OK");
header("Location: $zip");
}
}
$Generator = new HelpGenerator($conf);
$Generator->prepareTmp();
$Generator->generate();
$zip = TEMP_DIR.'/help.zip';
$Generator->createArchive($zip);
$Generator->redirectToZip($zip);

View File

@ -0,0 +1,96 @@
<?php
/* Ace editor plugin for Dokuwiki
* Copyright © 2011, 2012 Institut Obert de Catalunya
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* Ths program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
if (!defined('DOKU_INC')) die();
require_once DOKU_INC.'lib/plugins/action.php';
class action_plugin_aceeditor extends DokuWiki_Action_Plugin {
public function register(Doku_Event_Handler $controller){
$controller->register_hook('DOKUWIKI_STARTED', 'AFTER',
$this, 'handle_dokuwiki_started');
$controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE',
$this, 'handle_tpl_metaheader_output');
}
public function handle_dokuwiki_started(Doku_Event $event, $param) {
global $INFO, $JSINFO;
$wraplimit = trim($this->getConf('wraplimit'));
$xmltags = $this->getConf('xmltags');
$xmltags = ($xmltags ? explode(',', $xmltags) : array());
$JSINFO['plugin_aceeditor'] = array(
'default' => $this->getConf('default'),
'highlight' => $this->getConf('highlight'),
'wraplimit' => $wraplimit ? (int) $wraplimit : null,
'colortheme' => $this->getConf('colortheme'),
'latex' => $this->getConf('latex'),
'markdown' => $this->getConf('markdown'),
'mdpage' => substr($INFO['id'], -3) == '.md',
'xmltags' => $xmltags,
);
}
public function handle_tpl_metaheader_output(Doku_Event $event, $param) {
global $ACT;
if (!in_array($ACT, array('edit', 'create', 'source', 'preview',
'locked', 'draft', 'recover'))) {
return;
}
if (!$this->has_jquery() and $this->getConf('loadjquery')) {
$jqueryurl = '//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js';
$this->link_script($event, $jqueryurl);
$this->include_script($event, '$.noConflict();');
}
if (file_exists(DOKU_INC.'lib/plugins/aceeditor/build.js')) {
$this->link_script($event, DOKU_BASE.'lib/plugins/aceeditor/build.js');
} else {
$this->link_script($event, DOKU_BASE.'lib/plugins/aceeditor/vendor/require.js');
$this->link_script($event, DOKU_BASE.'lib/plugins/aceeditor/scripts/init.js');
}
// Workaround for conflict with syntaxhighlighter3 plugin
$this->include_script($event, 'window.require = undefined;');
}
public function has_jquery() {
$version = getVersionData();
$date = str_replace('-', '', $version['date']);
return (int) $date > 20110525;
}
private function include_script($event, $code) {
$event->data['script'][] = array(
'type' => 'text/javascript',
'charset' => 'utf-8',
'_data' => $code,
);
}
private function link_script($event, $url) {
$event->data['script'][] = array(
'type' => 'text/javascript',
'charset' => 'utf-8',
'src' => $url,
);
}
}

View File

@ -0,0 +1,13 @@
Файл ложится в корневую директорию Dokuwiki.
Требует установленый языковой плагин в Dokuwiki.
Требует права на запись в папку Dokuwiki так как создает в ней временную директорию для своих нужд.
Для работы генератора достаточно обратиться к нему по http и в ответ он отдаст архив с готовыой справкой.
Так же необходимо добавить обозначение нового языка в поле "Список поддерживаемых языков "
http://stbhelp.iptv.infomir.com.ua/doku.php?id=start&do=admin&page=config
Рядом с этой папкой должна появиться новая для нового языка
79.142.197.72
/var/www/stbhelp.iptv.infomir.com.ua/data/pages/ru

View File

@ -0,0 +1 @@
node http.server.js

14
mag/tools/http.server.js Normal file
View File

@ -0,0 +1,14 @@
/**
* HTTP static file server
* @author Stanislav Kalashnik <sk@infomir.eu>
*/
'use strict';
var files = new (require('node-static')).Server(require('path').join(__dirname, '/..'));
require('http').createServer(function (request, response) {
request.addListener('end', function () {
files.serve(request, response);
}).resume();
}).listen(8080);

69
mag/tools/models.js Normal file
View File

@ -0,0 +1,69 @@
/**
*
* @author Aleynikov Boris <aleynikov.boris@gmail.com>.
*/
var path = require('path'),
fs = require('fs'),
configPath = path.join(process.cwd(), '..', 'public', 'config.js'),
//
configuration = {},
PATH_IMG_PUBLIC ='',
PATH_SYSTEM = ''
;
Array.prototype.shuffle = function () {
var n = this.length,
i, tmp;
while ( n-- ) {
i = Math.floor(n * Math.random());
tmp = this[i];
this[i] = this[n];
this[n] = tmp;
}
return this;
};
function extend (target, source, override) {
var _target = (override === false ? extend({}, target) : target || {});
for (var prop in source) {
if ( typeof _target[prop] === 'object' && typeof source[prop] === 'object' && !Array.isArray(_target[prop]) && !Array.isArray(source[prop]) ) {
_target[prop] = extend(_target[prop], source[prop], override);
} else {
_target[prop] = source[prop];
}
}
return _target;
}
function getCurrentLanguage () {
return 'en';
}
fs.readFile(configPath, 'utf8', function ( error, data ) {
var copy,
idx = data.indexOf('var menu = {'),
codeText = data.slice(idx);
idx = codeText.indexOf('config = extend(config, models[gSTB.GetDeviceModelExt()]);');
codeText = codeText.slice(0, idx);
eval(codeText);
for ( model in models ) {
copy = JSON.parse(JSON.stringify(config));
models[model] = extend(copy, models[model]);
console.log(model + ' ' + models[model].logoImagePath);
}
fs.writeFileSync('models.json', JSON.stringify(models, null, 4));
console.log('Write to models.json');
});

28
mag/tools/package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "portal-tools",
"version": "0.1.0",
"description": "command-line utils for the stb portal management",
"keywords": [
"stb",
"portal",
"command",
"utils"
],
"author": "Stanislav Kalashnik <sk@infomir.eu>",
"repository": {},
"scripts": {
"test": "echo \"no test specified\""
},
"readme": "",
"dependencies": {
"adm-zip": "0.4.x",
"cheerio": "0.12.0",
"commander": "2.6.*",
"pofile": "0.2.*",
"node-static": "0.7.x",
"request": "2.51.x",
"uglify-js": "2.4.x",
"wrench": "1.5.x",
"clean-css": "2.2.x"
}
}

14
mag/tools/readme.md Normal file
View File

@ -0,0 +1,14 @@
gettext.js - NodeJS скрипт генерации js файлов на основании gettext po файлов
пример вызова:
node gettext.js -f "../public/app/dlman/lang/ru.po"
получение справки:
node gettext.js --help
build.gettext.cmd - скрипт автоматической генерации js файлов на основании gettext po файлов для всего проекта
вызывается без параметров
release.js - NodeJS скрипт сборки релиза с вычленением всех зависимостей и склейки в общий файл для каждого html файла
пример вызова (пути по умолчанию):
node release.js
пример вызова (пути в явном виде):
node release.js -s "../../current_portal_path" -d "../../new_minified_version"

153
mag/tools/release.js Normal file
View File

@ -0,0 +1,153 @@
/**
* Module to prepare minimized and compressed version of page dependence files
* @author Stanislav Kalashnik <sk@infomir.eu>
*/
//'use strict';
var program = require('commander'),
cheerio = require('cheerio'),
wrench = require('wrench'),
uglify = require('uglify-js'),
path = require('path'),
cleanCss = new (require('clean-css'))({noAdvanced:true, noRebase:true}),
fs = require('fs'),
exec = require('child_process').execSync,
gitHash = fs.existsSync(path.join(__dirname, '..', '.git')) && exec('git rev-parse HEAD').toString().trim();
// console colors
var red = '\u001b[31m',
bold = '\u001b[1m',
cyan = '\u001b[36m',
green = '\u001b[32m',
reset = '\u001b[0m';
// all used js files
var jsUsedList = {};
// CLI init
program.version('0.1')
.option('-s, --src [PATH]', 'source directory with files to proceed [..]', '..')
.option('-d, --dst [PATH]', 'destination directory for the result build [../mini]', '..' + path.sep + 'mini')
.parse(process.argv);
// the po file is given
if ( !program.src || typeof program.src !== 'string' ||
!program.dst || typeof program.dst !== 'string' ) { console.log('Not enough parameters!'); return; }
// normalize
program.src = path.resolve(program.src);
program.dst = path.resolve(program.dst);
// report
console.log(cyan + 'src:\t' + reset + bold + program.src + reset);
console.log(cyan + 'dst:\t' + reset + bold + program.dst + reset + "\n");
// prepare
wrench.rmdirSyncRecursive(program.dst, true);
wrench.mkdirSyncRecursive(program.dst);
// report
console.log(green + 'ok\t' + reset + 'prepared the destination directory');
// dirs
wrench.copyDirSyncRecursive(program.src + path.sep + 'public', program.dst + path.sep + 'public');
wrench.copyDirSyncRecursive(program.src + path.sep + 'system', program.dst + path.sep + 'system');
// files
fs.writeFileSync(program.dst + path.sep + 'index.html', fs.readFileSync(program.src + path.sep + 'index.html', {encoding:'utf8'}), {encoding:'utf8'});
fs.writeFileSync(program.dst + path.sep + 'services.html', fs.readFileSync(program.src + path.sep + 'services.html', {encoding:'utf8'}), {encoding:'utf8'});
fs.writeFileSync(program.dst + path.sep + 'rules.js', fs.readFileSync(program.src + path.sep + 'rules.js', {encoding:'utf8'}), {encoding:'utf8'});
// report
console.log(green + 'ok\t' + reset + 'cloned the source directory to the destination');/**/
console.log(green + 'ok\t' + reset + 'cleaning gettext localization files');
// remove all po files
walk(program.dst, '.po').forEach(function(item){
fs.unlinkSync(item);
});
// recursively read directories contents
// and get all html files
walk(program.dst, '.html').forEach(function(item){
var htmlFile = fs.readFileSync(item, {encoding:'utf8'});
var jsName = path.dirname(item) + path.sep + path.basename(item, '.html') + '.min.js';
var jsData = [];
var scripts = [];
// screen resolution correction
htmlFile = htmlFile.replace(/WINDOW_HEIGHT/g, 'screen.height');
htmlFile = htmlFile.replace(/WINDOW_WIDTH/g, 'screen.width');
// parse
var $ = cheerio.load(htmlFile, {ignoreWhitespace:false, xmlMode:false});
// find and remove scripts
$('script').each(function(){
// only in case of include
if ( $(this).attr('src') !== undefined && $(this).attr('src') !== 'rules.js' ) {
var src = path.normalize(path.dirname(item) + path.sep + $(this).attr('src'));
jsUsedList[src] = true;
scripts.push(src);
$(this).remove();
}
});
// report
console.log(green + 'ok\t' + reset + 'processed: ' + bold + path.relative(program.dst, item) + reset);
// add one general
if ( scripts.length > 0 ) {
scripts.forEach(function(script){
console.log('\t\tscript: ' + path.relative(program.dst, script));
jsData.push(fs.readFileSync(script, {encoding:'utf8'}).trim());
});
$('head').append('\n\t<script type="text/javascript" src="' + path.basename(item, '.html') + '.min.js' + '"></script>\n');
fs.writeFileSync(jsName, uglify.minify(jsData.join('\n\n\n'), {fromString:true, mangle:false}).code, {encoding:'utf8'});
}
htmlFile = $.html();
// resave
fs.writeFileSync(item, htmlFile, {encoding:'utf8'});
});
// clear all used js files
for ( var name in jsUsedList ) if ( jsUsedList.hasOwnProperty(name) ) fs.unlinkSync(name);
// gstb
fs.unlinkSync(program.dst + path.sep + 'system' + path.sep + 'gstb.js');
console.log(green + 'ok\t' + reset + 'cleared all used js files');
console.log(green + 'ok\t' + reset + 'prepare to compile language files');
// recursively read directories contents
// and get all js files to minimize
walk(program.dst, '.js').forEach(function(item){
if ( item.indexOf('.min.js') === -1 && item.indexOf('rules.js') === -1 ) {
fs.writeFileSync(
item,
uglify.minify(fs.readFileSync(item, {encoding:'utf8'}), {fromString:true, mangle:false}).code,
{encoding:'utf8'}
);
}
});
console.log(green + 'ok\t' + reset + 'prepare to minify css files');
// minify css files
walk(program.dst, '.css').forEach(function(item){
fs.writeFileSync(
item,
cleanCss.minify(fs.readFileSync(item, {encoding:'utf8'})),
{encoding:'utf8'}
);
});
// save build info
fs.writeFileSync(program.dst + path.sep + 'info.json', JSON.stringify({
time: (new Date()).toUTCString(),
hash: gitHash
}, null, '\t'), {encoding:'utf8'});
function walk ( dir, ext ) {
var results = [];
var list = fs.readdirSync(dir);
list.forEach(function ( file ) {
file = dir + path.sep + file;
var stat = fs.statSync(file);
if ( stat && stat.isDirectory() ) results = results.concat(walk(file, ext));
else if ( path.extname(file) === ext ) results.push(file);
});
return results;
}

View File

@ -0,0 +1,110 @@
/**
* STB Proxy desktop browser (client) part
* @constructor
* @author Stanislav Kalashnik <sk@infomir.eu>
*/
function proxyClient () {
/**
* proxy instance configuration
* @namespace
*/
var config = {
/** node.js server address */
host : '127.0.0.1',
/** http server port */
port : 8800,
/** session name */
name : 'anonymous',
/** cached url for posting requests */
urlPost : null,
/** cached url for info collecting */
urlInfo : null
};
// single ajax object for performance
var xhr = new XMLHttpRequest();
/**
* Prepares the connection
* @param {Object} options set of initialization parameters (host, port, name, urlPost, urlInfo)
*/
this.init = function ( options ) {
// validate and iterate input
if ( options ) for ( var name in options ) {
// rewrite defaults
if ( options.hasOwnProperty(name) ) config[name] = options[name];
}
// cache final request urls
config.urlPost = 'http://' + config.host + ':' + config.port + '/' + config.name;
config.urlInfo = 'http://' + config.host + ':' + config.port + '/info/' + config.name;
};
/**
* Sends a sync request to the STB device from the desktop browser
* @param {Object} data JSON data to send
* @return {*} execution result from the STB
*/
this.send = function ( data ) {
// mandatory init check
if ( !config.urlPost ) return false;
// prepare
var time = +new Date(),
response;
// make request
xhr.open('post', config.urlPost, false);
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.send(JSON.stringify(data));
// proceed the result
try {
response = JSON.parse(xhr.responseText);
} catch ( e ) {
response = {error:e};
}
// detailed report
console.groupCollapsed('%c%s\t%c%d/%d ms',
'color:' + (response.error ? 'red' : 'green'), data.method || data.code || 'unhandled STB call',
'color:#aaa;font-weight:normal', response.time || 0, +new Date() - time);
console.log(data);
console.log(response.error || response.data);
console.groupEnd();
// ready
return response.data;
};
/**
* Wrapper to send a line of js code to eval on the STB device
* @param {string} code javascript source code to execute on the device
* @return {*} execution result from the STB
*/
this.eval = function ( code ) {
return this.send({type:'eval', code:code});
};
/**
* Wrapper to send one function of js code with arguments to eval on the STB device
* @param {string} method javascript function name (like "gSTB.Debug")
* @param {Array} params list of the function arguments
* @return {*} execution result from the STB
*/
this.call = function ( method, params ) {
return this.send({type:'call', method:method, params:params});
};
/**
* Gets the detailed info about the current connection
* @return {{active:Boolean, count:Number}|{active:Boolean}|Boolean}
*/
this.info = function () {
// mandatory init check
if ( !config.urlInfo ) return false;
// make request
xhr.open('get', config.urlInfo, false);
xhr.send();
return JSON.parse(xhr.responseText || false);
};
}

View File

@ -0,0 +1,84 @@
/**
* STB Proxy device (server) side
* @constructor
* @author Stanislav Kalashnik <sk@infomir.eu>
*/
function ProxyServer () {
/**
* proxy instance configuration
* @namespace
*/
var config = {
/** node.js server address */
host : '127.0.0.1',
/** websocket server port */
port : 8900,
/** session name */
name : 'anonymous'
};
/**
* Prepares the connection
* @param {Object} options set of initialization parameters (host, port, name)
*/
this.init = function ( options ) {
// validate and iterate input
if ( options ) for ( var name in options ) {
// rewrite defaults
if ( options.hasOwnProperty(name) ) config[name] = options[name];
}
// establish the connection
config.socket = new WebSocket('ws://' + config.host + ':' + config.port + '/' + config.name);
// event hook
config.socket.onopen = function(){
console.log('socket.onopen', config.name);
};
// event hook
config.socket.onclose = function(){
console.log('socket.onclose', config.name);
};
// message from a desktop browser
config.socket.onmessage = function ( message ) {
console.log('socket.onmessage', config.name);
// prepare
var result = {time:+new Date()},
request;
// proceed the message
try {
request = JSON.parse(message.data || false);
// valid incoming request
if ( request && ['call', 'eval'].indexOf(request.type) !== -1 ) {
// exec types
if ( request.type === 'call' ) {
result.data = eval(request.method).apply(window, request.params);
} else if ( request.type === 'eval' ) {
result.data = eval(request.code);
}
} else {
result.error = 'invalid incoming request';
}
} catch ( e ) {
console.log(e);
result.error = e;
}
// time taken
result.time = +new Date() - result.time;
// wrap and send back
config.socket.send(JSON.stringify(result));
}
};
/**
* Finish the connection
*/
this.close = function () {
config.socket.close();
}
}

View File

@ -0,0 +1,44 @@
<!doctype html>
<html>
<head>
<title>Debug entry point</title>
<meta charset='utf-8'>
<link rel="shortcut icon" href="https://www.iconfinder.com/icons/3693/download/png/64"/>
<style type="text/css">
html, body { height: 100%; background:#000; color:#fff; margin:0; padding:0; font-family:Verdana,sans-serif; font-size:20px }
/* table cell spacing/padding reset */
table { border:0; border-collapse:collapse }
table td { padding:0 }
/* meta-classes */
.maxh { height:100% }
.maxw { width:100% }
a { text-decoration:none }
</style>
<script type="text/javascript">
</script>
</head>
<body>
<table class="maxh maxw">
<tr>
<td>
<!--header-->
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td>
<!--footer-->
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,96 @@
/**
* STB Proxy server node.js part
* handles all requests between desktop browser (client) and server (stb device)
* @author Stanislav Kalashnik <sk@infomir.eu>
*/
// globals
var WebSocketServer = require('ws').Server,
wsPool = require('./wspool.js'),
http = require('http'),
fs = require('fs');
// connection ports
var portHttp = 8800, // http server
portWss = 8900; // websocket server
// files allowed to be served
var fileList = ['client.js', 'server.js'];
// WebSocket server creation
wss = new WebSocketServer({port:portWss});
wss.on('connection', function(socket) {
// new awaiting instance of WebSocket in the pool
wsPool.add(socket.upgradeReq.url.slice(1), socket);
});
console.log('port %d accepts WebSocket connections', portWss);
// simple http listener
http.createServer(function(request, response){
console.log('http\t%s\t%s', request.method, request.url);
// prepare request query
var query = request.url.slice(1).split('/');
switch ( request.method ) {
// simple serve info/file requests
case 'GET':
// first param holds the command name
switch ( query[0] ) {
// serving files
case 'file':
// one of the allowed files
if ( fileList.indexOf(query[1]) !== -1 ) {
response.writeHead(200, {'Content-Type':'application/javascript; charset=utf-8'});
response.end(fs.readFileSync(query[1]));
}
break;
// get connection info
case 'info':
//var wsItem = wsList.get(query[1]);
response.writeHead(200, {'Content-Type':'application/json; charset=utf-8'});
response.end(JSON.stringify(wsPool.info(query[1])));
break;
// show help page
default:
// not valid url or root
response.writeHead(200, {'Content-Type':'text/html; charset=utf-8'});
response.end(fs.readFileSync('start.html'));
}
break;
// security info call
case 'OPTIONS':
//TODO: investigate why doesn't work
response.writeHead(200, {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Credentials' : 'true',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS',
'Access-Control-Allow-Headers' : 'content-type',
'Access-Control-Max-Age' : 1800
});
response.end();
break;
// accept connections from desktop clients
case 'POST':
var post = '';
// append all chunks
request.on('data', function(data){ post += data; });
// everything is ready to send to the STB
request.on('end', function(){
// make a call
if ( !wsPool.send(query[0], post, response) ) {
// no available connections so close
response.end(JSON.stringify({error:'no connections'}));
}
});
break;
default:
response.end('wrong request!');
}
}).listen(portHttp);
console.log('port %d accepts HTTP connections\n', portHttp);

View File

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>client.a</title>
<script type="text/javascript" src="http://192.168.1.71:8800/file/client.js"></script>
<script type="text/javascript">
var name = document.title,
proxy = new proxyClient();
window.onload = function(){
document.body.innerHTML = name;
proxy.init({name:'a', host:'192.168.1.71'});
};
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>client.b</title>
<script type="text/javascript" src="http://192.168.1.71:8800/file/client.js"></script>
<script type="text/javascript">
var name = document.title,
proxy = new proxyClient();
window.onload = function(){
document.body.innerHTML = name;
proxy.init({name:'b', host:'192.168.1.71'});
};
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>server.a</title>
<script type="text/javascript" src="http://192.168.1.71:8800/file/server.js"></script>
<script type="text/javascript">
var name = document.title,
proxy = new proxyServer();
window.onload = function(){
document.body.innerHTML = name;
proxy.init({name:'a', host:'192.168.1.71'});
};
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>server.b</title>
<script type="text/javascript" src="http://192.168.1.71:8800/file/server.js"></script>
<script type="text/javascript">
var name = document.title,
proxy = new proxyServer();
window.onload = function(){
document.body.innerHTML = name;
proxy.init({name:'b', host:'192.168.1.71'});
};
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,109 @@
/**
* WebSocket pool
* wraps all the work with ws instances
* @author Stanislav Kalashnik <sk@infomir.eu>
*/
// named WebSocket list
var pool = {};
// exports the wrapper object
module.exports = {
/**
* New WebSocket creation
* @param {string} name unique identifier for session
* @param {Object} socket websocket resource
* @return {boolean} true if was deleted successfully
*/
add : function ( name, socket ) {
var self = this;
// check input
if ( name && socket ) {
console.log('ws\tINIT\t[%s]\tconnection', name);
// main data structure
pool[name] = {
socket : socket,
time : Math.round(+new Date()/1000),
count : 0,
active : true
};
// disable link on close
pool[name].socket.on('close', function() {
self.remove(name);
});
// await for an answer
pool[name].socket.on('message', function(message) {
// has link to talk back
if ( pool[name].response ) {
console.log('ws\tGET\t[%s]\tmessage\t%s', name, message);
pool[name].response.end(message);
}
});
return true;
}
// failure
console.log('ws\tINIT\t[%s]\tfail to connect (wrong name or link)', name);
return false;
},
/**
* Clear resources on WebSocket deletion
* @param {string} name session name
* @return {boolean} true if was deleted successfully
*/
remove : function ( name ) {
// valid connection
if ( name in pool ) {
console.log('ws\tEXIT\t[%s]\tclose', name);
return delete pool[name];
}
// failure
console.log('ws\tDEL\t[%s]\tfail to remove (invalid connection)', name);
return false;
},
/**
* Detailed information of the named WebSocket instance
* @param {string} name session name
* @return {{active:Boolean, count:Number}|{active:Boolean}}
*/
info : function ( name ) {
// valid connection
if ( name in pool ) {
return {
active : pool[name].active,
count : pool[name].count
};
}
// failure
return {active:false};
},
/**
*
* @param {string} name session name
* @param {string} data post data from browser to STB server
* @param {ServerResponse} response link to HTTP response object to send back data
* @return {boolean} true if was send successfully
*/
send : function ( name, data, response ) {
// valid connection
if ( name in pool && pool[name].active ) {
console.log('ws\tSEND\t[%s]\tmessage\t%s', name, data);
// store link to talk back when ready
pool[name].response = response;
// actual post
pool[name].socket.send(data);
pool[name].count++;
return true;
}
// failure
console.log('ws\tSEND\t[%s]\tfail to send (invalid connection)', name);
return false;
}
};