├── .eslintrc.json ├── .gitignore ├── ReadMe.txt ├── app ├── ahelper.js ├── alert.js ├── app.js ├── sound.js ├── translation-en.js └── version.js ├── build.bat ├── build.sh ├── cache_detection.js ├── compiler └── compiler.jar ├── css ├── bootstrap-navbar-hack.css ├── bootstrap-orig.css ├── bootstrap-theme.css ├── bootstrap.css └── style.css ├── customization ├── hmtg.js └── tutoring.js ├── dep ├── adapter.js ├── adapter.min.js ├── angular-translate-loader-static-files-orig.js ├── angular-translate-loader-static-files-orig.min.js ├── angular-translate-loader-static-files.js ├── angular-translate-loader-static-files.min.js ├── angular-translate-orig.js ├── angular-translate.js ├── angular-translate.min-orig.js ├── angular-translate.min.js ├── angular.js ├── angular.min.js ├── empty-line.js ├── hmtg.min.js ├── html2canvas.js ├── html2canvas.min.js ├── lazy-helper.js ├── mediasoup-client.js ├── mediasoup-client.min.js ├── ocLazyLoad-orig.js ├── ocLazyLoad-orig.min.js ├── ocLazyLoad.js ├── ocLazyLoad.min.js ├── protoo-client.js ├── protoo-client.min.js ├── ui-bootstrap-tpls-0.12.0-orig.js ├── ui-bootstrap-tpls-0.12.0-orig.min.js ├── ui-bootstrap-tpls-0.12.0.js └── ui-bootstrap-tpls-0.12.0.min.js ├── docs ├── 1-1.png ├── 2-0a.png ├── 2-0b.png ├── 2-0c.png ├── 2-1.png ├── 2-10.png ├── 2-11.png ├── 2-12.png ├── 2-13.png ├── 2-14.png ├── 2-15.png ├── 2-16.png ├── 2-17.png ├── 2-18.png ├── 2-19.png ├── 2-2.png ├── 2-20.png ├── 2-21.png ├── 2-22.png ├── 2-23.png ├── 2-24.png ├── 2-25.png ├── 2-26.png ├── 2-27.png ├── 2-28.png ├── 2-29.png ├── 2-3.png ├── 2-30.png ├── 2-31.png ├── 2-32.png ├── 2-33.png ├── 2-34.png ├── 2-35.png ├── 2-36.png ├── 2-4.png ├── 2-5.png ├── 2-6.png ├── 2-7.png ├── 2-8.png ├── 2-9.png ├── 3-1.png ├── 3-10.png ├── 3-11.png ├── 3-12.png ├── 3-13.png ├── 3-14.png ├── 3-15.png ├── 3-16.png ├── 3-2.png ├── 3-3.png ├── 3-4.png ├── 3-5.png ├── 3-6.png ├── 3-7.png ├── 3-8.png ├── 3-9.png ├── index.htm ├── index_ja.htm ├── index_ko.htm ├── index_zh_CN.htm └── index_zh_TW.htm ├── fonts ├── MaterialIcons-Regular.woff2 ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff └── glyphicons-halflings-regular.woff2 ├── img ├── close.png ├── cursor.png ├── icon_dummy_16x16.png ├── icon_dummy_32x32.png ├── icon_event_ongoing.png ├── icon_event_upcoming.png ├── icon_file.png ├── icon_file_encrypted.png ├── icon_file_encrypted_shared.png ├── icon_file_read.png ├── icon_file_read_encrypted.png ├── icon_file_read_encrypted_shared.png ├── icon_file_read_shared.png ├── icon_file_shared.png ├── icon_im.png ├── icon_im_add.png ├── icon_im_delete.png ├── icon_im_emoticon.png ├── icon_im_file.png ├── icon_im_file_large.png ├── icon_im_font.png ├── icon_im_invite.png ├── icon_im_large.png ├── icon_im_launch.png ├── icon_im_log.png ├── icon_im_log_large.png ├── icon_im_send.png ├── icon_im_transfer.png ├── icon_im_visit.png ├── icon_main.png ├── icon_main2.png ├── icon_main3.png ├── icon_missed_call.png ├── icon_mobile.png ├── icon_mystatus.png ├── icon_server.png ├── icon_server2.png ├── icon_server_mmc.png ├── icon_share_playback.png ├── icon_share_playback_userid.png ├── icon_signin.png ├── icon_sipim1.png ├── icon_sipim2.png ├── icon_sipim_large.png ├── icon_textmark_bold.png ├── icon_textmark_bold2.png ├── icon_textmark_italic.png ├── icon_textmark_italic2.png ├── icon_textmark_left.png ├── icon_textmark_left2.png ├── icon_textmark_right.png ├── icon_textmark_right2.png ├── icon_textmark_symbol.png ├── icon_textmark_symbol2.png ├── icon_user.png ├── icon_user_away.png ├── icon_user_busy.png ├── icon_user_folded.png ├── icon_user_inmeeting.png ├── icon_user_mobile.png ├── icon_user_offline.png ├── icon_user_online.png ├── icon_user_open.png ├── icon_user_unfolded.png ├── icon_user_visitor.png ├── icon_user_web.png ├── jnagent_16x16.png ├── jnagent_32x32.png ├── jnagent_48x48.png ├── jnagent_512x512.png ├── jnagent_72x72.png ├── logo.png ├── mark │ ├── alphatest.png │ ├── apple.png │ ├── emoji-crying.png │ ├── emoji-smile.png │ ├── emoji-sunglass.png │ ├── logo.png │ ├── msgr.png │ └── star.png ├── pointer.png ├── search.png └── vcli.png ├── index-dummy.htm ├── index.htm ├── joinnet ├── advanced.js ├── audio_capture.js ├── audio_codec.js ├── audio_playback.js ├── board.js ├── browser.js ├── chat.js ├── dt.js ├── jhelper.js ├── joinnet.js ├── media_control.js ├── mediasoup_webrtc.js ├── mypicture.js ├── playback.js ├── reconnect_name.js ├── userlist.js ├── video_capture.js ├── video_codec.js └── video_playback.js ├── lang ├── translation-base.json ├── translation-en.json ├── translation-ja.json ├── translation-ko.json ├── translation-zh_CN.json └── translation-zh_TW.json ├── lazy_htm ├── _internal_option_test.htm ├── joinnet_browser.htm ├── joinnet_chat.htm ├── joinnet_chat2.htm ├── joinnet_image_bar.htm ├── joinnet_jnr.htm ├── joinnet_playback.htm ├── joinnet_rdc.htm ├── joinnet_sdt.htm ├── joinnet_stat.htm ├── joinnet_transcoding.htm ├── joinnet_video.htm ├── navitem_jnj.htm ├── navitem_log.htm ├── navitem_missed_call.htm ├── navitem_prompt.htm ├── navitem_reconnect_name.htm ├── option_demo.htm ├── option_joinnet.htm ├── option_msgr.htm ├── option_mypicture.htm ├── option_nativeapp.htm ├── option_score.htm ├── option_url.htm ├── option_webapp.htm └── option_webrtc.htm ├── lazy_js ├── _codepage_encoding.js ├── _html2canvas.js ├── _internal_option_test.js ├── _pdf-lib.js ├── _pdf.js ├── joinnet_browser.js ├── joinnet_chat.js ├── joinnet_dt.js ├── joinnet_jnr.js ├── joinnet_playback.js ├── joinnet_stat.js ├── joinnet_transcoding.js ├── joinnet_video.js ├── modal_change_jnr_password.js ├── modal_download_complete.js ├── modal_edit_profile.js ├── modal_image_mark.js ├── modal_import_media.js ├── modal_jeditor.js ├── modal_move_office.js ├── modal_msgr_signin.js ├── modal_pick_user.js ├── modal_rename.js ├── modal_share_jnr.js ├── modal_short_message.js ├── modal_snapshot.js ├── modal_style.js ├── modal_upload_slide.js ├── modal_view_record.js ├── navitem_jnj.js ├── navitem_log.js ├── navitem_missed_call.js ├── navitem_prompt.js ├── navitem_reconnect_name.js ├── option_joinnet.js ├── option_msgr.js ├── option_mypicture.js ├── option_url.js ├── option_webapp.js └── option_webrtc.js ├── lazy_js_min ├── _codepage_encoding.min.js ├── _html2canvas.min.js ├── _pdf-lib.min.js └── _pdf.min.js ├── manifest.json ├── media ├── alert.mp3 ├── alert.ogg ├── alert.wav ├── online.mp3 ├── online.ogg ├── online.wav ├── ringin.mp3 ├── ringin.ogg ├── ringin.wav ├── small.mp4 ├── small.webm ├── speaker.mp3 ├── speaker.ogg ├── speaker.wav ├── type.mp3 ├── type.ogg └── type.wav ├── msgr ├── checkIM.js ├── checkMessage.js ├── icon.js ├── imDlg.js ├── jnagentDlg.js ├── mhelper.js ├── missedCall.js └── msgr.js ├── readme.md ├── sw.js ├── template ├── ChangeJnrPassword.htm ├── DeleteSlide.htm ├── DownloadComplete.htm ├── EditProfile.htm ├── ImageMark.htm ├── ImportMedia.htm ├── MeetingControl.htm ├── MoveOffice.htm ├── PickUser.htm ├── PlaybackJumpTo.htm ├── PollRequest.htm ├── PollResult.htm ├── PromptPassword.htm ├── Rename.htm ├── ShareJNR.htm ├── ShortMessage.htm ├── Snapshot.htm ├── Style.htm ├── UploadSlide.htm ├── ViewRecord.htm ├── WebOfficeVisitor.htm ├── imTitle.htm ├── jeditor.htm └── msgrSignin.htm ├── whiteboard_new.js └── worker ├── avc-codec.js ├── avc.js ├── dt_decode.js ├── dt_encode.js ├── g711_decode.js ├── g711_encode.js ├── gunzip.min.js ├── gzip.min.js ├── gzip_helper.js ├── h264_decode.js ├── libopus.js ├── ogv-decoder-video-vp8.js ├── openh264_decoder.js ├── openh264_encoder.js ├── opus.js ├── opus_decode.js ├── opus_encode.js ├── pdf.worker.js ├── test_worker.js ├── vp8_decode.js ├── vpx_decoder.js ├── vpx_encoder.js ├── worker_interval.js ├── worker_interval_40.js ├── worker_timeout.js ├── worklet-playback.js ├── worklet-record.js ├── zlib.min.js └── zlib_and_gzip.min.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true 7 | }, 8 | "parserOptions": { 9 | "ecmaFeatures": { 10 | "jsx": true 11 | }, 12 | "sourceType": "module" 13 | }, 14 | "rules": { 15 | "no-const-assign": "warn", 16 | "no-this-before-super": "warn", 17 | "no-undef": "warn", 18 | "no-unreachable": "warn", 19 | "no-unused-vars": "warn", 20 | "constructor-super": "warn", 21 | "valid-typeof": "warn" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | 5 | **/*DS_Store 6 | 7 | **/*.js.map 8 | **/*.min.css 9 | **/*.css.map 10 | **/*.min.js 11 | !dep/*.min.js 12 | !lazy_js_min/_*.min.js 13 | !worker/*.min.js 14 | 15 | hmtgs.js 16 | 17 | worker/min/ 18 | dist/ 19 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | * Test 2 | 1. Set up a web server (such as xampp Apache) at the local computer 3 | 2. Add an aliase such as 4 | 5 | Require all granted 6 | AllowOverride All 7 | Order allow,deny 8 | Allow from all 9 | 10 | Alias /webjoinnet-angularjs "C:/yourfolder/webjoinnet-angularjs" 11 | 3. The web App can be tested at http://localhost/webjoinnet-angularjs/ 12 | 13 | * Debug 14 | 1. In the file index-dummy.htm, there are two groups of 17 | 18 | They are used for production. 19 | 20 | The second group contains more entries. 21 | 2. At the bottom of file index.htm, there are two lines: 22 | 23 | 24 | This part can be replaced with the second group of 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /joinnet/advanced.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .controller('JoinNetAdvancedCtrl', ['$scope', '$translate', 'hmtgHelper', '$modal', 10 | '$rootScope', 'appSetting', 'hmtgSound', 11 | function ($scope, $translate, hmtgHelper, $modal, $rootScope, appSetting, hmtgSound) { 12 | $scope.w = appSetting; 13 | 14 | $scope.simulate_disconnect = function () { 15 | hmtg.jnkernel.jn_command_simulate_disconnect(); 16 | } 17 | 18 | $scope.simulate_reconnect_overwrite = function () { 19 | hmtg.util.log('simulate to disconnect and reconnect immediately'); 20 | hmtgHelper.inside_angular++; 21 | hmtgSound.ShowInfoPrompt(function () { return $translate.instant('ID_LEAVE_AND_RECONNECT') }, 10); 22 | hmtg.jnkernel.jn_command_QuitConnection(); 23 | hmtg.jnkernel.jn_command_initconnectmedia(true); 24 | hmtgHelper.inside_angular--; 25 | } 26 | 27 | } 28 | ]) 29 | 30 | ; 31 | -------------------------------------------------------------------------------- /joinnet/audio_codec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .service('audio_codec', ['$translate', 'appSetting', 'hmtgHelper', 'hmtgAlert', '$rootScope', 'hmtgSound', 10 | function ($translate, appSetting, hmtgHelper, hmtgAlert, $rootScope, hmtgSound) { 11 | var _audio_codec = this; 12 | this.audio_codecs = []; 13 | this.max_opus_bitrate = 256000; 14 | this.min_opus_bitrate = 12000; 15 | this.opus_bitrate_pos = 100; 16 | this.opus_bitrate = 0; 17 | this.g711_bitrate = 67520; // ((8 * 50ms) + 21 + 1) * 8 / 50ms = 422 * 8 / 50 = 67520 18 | //this.g711_bitrate_str = '' + ((this.g711_bitrate / 1000) >>> 0) + 'kbps'; 19 | this.g711_bitrate_str = '' + hmtgHelper.number2gmk(this.g711_bitrate) + 'bps'; 20 | this.audio_codec = 0; 21 | this.audio_bitrate_str = ''; 22 | 23 | this.launch_from_jnj = function () { 24 | this.opus_bitrate = 0; 25 | this.audio_codec = 0; 26 | this.max_opus_bitrate = 256000; 27 | } 28 | 29 | this.reset = function () { 30 | this.audio_codecs = []; 31 | /* 32 | if(this.change_opus_bitrate_timerID) { 33 | clearTimeout(this.change_opus_bitrate_timerID); 34 | this.change_opus_bitrate_timerID = null; 35 | } 36 | if(this.change_audio_codec_timerID) { 37 | clearTimeout(this.change_audio_codec_timerID); 38 | this.change_audio_codec_timerID = null; 39 | } 40 | */ 41 | 42 | $rootScope.$broadcast(hmtgHelper.WM_UPDATE_USERLIST); 43 | } 44 | 45 | this.net_init_finished = function () { 46 | var array = hmtg.jnkernel._jn_audio_codec_array(); 47 | if(!array) return; 48 | var i; 49 | var my_codec = 0; 50 | var is_current_codec_valid = false; 51 | for(i = 0; i < array.length; i++) { 52 | var c = array[i]; 53 | if(c == hmtg.config.AUDIO_OPUS) { 54 | this.audio_codecs.push({ name: 'Opus', value: c }); 55 | my_codec = c; 56 | if(this.audio_codec == c) is_current_codec_valid = true; 57 | } else if(c == hmtg.config.AUDIO_G711) { 58 | this.audio_codecs.push({ name: 'G711', value: c }); 59 | if(!my_codec) my_codec = c; 60 | if(this.audio_codec == c) is_current_codec_valid = true; 61 | } 62 | } 63 | if(!is_current_codec_valid) this.audio_codec = my_codec; 64 | 65 | if(!this.audio_codec) { 66 | if(hmtg.jnkernel._jn_iWorkMode() == hmtg.config.NORMAL) 67 | hmtg.util.log('no common audio codec'); 68 | } 69 | 70 | this.is_opus_audio = this.audio_codec == hmtg.config.AUDIO_OPUS; 71 | this.max_opus_bitrate = hmtgHelper.get_opus_bitrate(); 72 | if(this.opus_bitrate < this.min_opus_bitrate || this.opus_bitrate > this.max_opus_bitrate) this.opus_bitrate = this.max_opus_bitrate; 73 | //this.opus_bitrate_str = '' + ((this.opus_bitrate / 1000) >>> 0) + 'kbps'; 74 | this.opus_bitrate_str = '' + hmtgHelper.number2gmk(this.opus_bitrate) + 'bps'; 75 | if(this.max_opus_bitrate < 13000) { 76 | this.can_change_opus_bitrate = false; 77 | } else { 78 | this.can_change_opus_bitrate = true; 79 | this.opus_bitrate_pos = (this.opus_bitrate - this.min_opus_bitrate) / (this.max_opus_bitrate - this.min_opus_bitrate) * 100; 80 | } 81 | 82 | } 83 | 84 | } 85 | ]) 86 | 87 | ; 88 | -------------------------------------------------------------------------------- /joinnet/browser.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .service('browser', ['$translate', 'appSetting', 'hmtgHelper', '$rootScope', '$sce', 'joinnetHelper', 'hmtgSound', 10 | function ($translate, appSetting, hmtgHelper, $rootScope, $sce, joinnetHelper, hmtgSound) { 11 | var _browser = this; 12 | this.url = this.url2 = ''; 13 | this.relay_url2 = ''; 14 | this.url2_url = ''; // the url when this url2 is set 15 | this.href = ''; 16 | this.loading_url2 = $sce.trustAsResourceUrl('loading.htm'); 17 | this.container = document.getElementById('browser_container'); 18 | this.history = []; 19 | this.history_idx = -1; 20 | this.is_fullscreen = false; 21 | this.request_fullscreen = this.container.requestFullscreen 22 | || this.container.msRequestFullscreen 23 | || this.container.mozRequestFullScreen 24 | || this.container.webkitRequestFullscreen 25 | ; 26 | this.LINK_MODE_GOTO = 1; 27 | this.LINK_MODE_LINK = 2; 28 | this.LINK_MODE_BACK = 3; 29 | this.LINK_MODE_FORWARD = 4; 30 | 31 | this.reset = function () { 32 | _browser.url = ''; 33 | _browser.url2 = $sce.trustAsResourceUrl('about:blank'); // must use this, empty string ('') not working to reset the cache 34 | _browser.url2_url = ''; 35 | _browser.is_new_url = true; // a url input from outside 36 | 37 | this.history = []; 38 | this.history_idx = -1; 39 | $rootScope.$broadcast(hmtgHelper.WM_BROWSER_URL); 40 | } 41 | 42 | this.callback_JointBrowsing = function (command_type, url) { 43 | if($rootScope.is_secure && appSetting.auto_https) { 44 | var scheme = hmtg.util.schemeURL(url); 45 | if(!scheme || scheme === 'http') { 46 | var old = url; 47 | if(!scheme) url = 'https://' + url; 48 | else url = 'https://' + url.slice(7); 49 | hmtgSound.ShowInfoPrompt(function () { 50 | return $translate.instant('ID_HTTP_TO_HTTPS').replace('#http#', old).replace('#https#', url); 51 | }, 10, false); 52 | } 53 | } 54 | this.append_history(url); 55 | this.displayURL(url); 56 | } 57 | 58 | this.displayURL = function(url) { 59 | // try to render loading.htm first 60 | this.url2 = _browser.loading_url2; 61 | 62 | _browser.is_new_url = true; // a url input from outside 63 | _browser.url2_url = _browser.url = url; 64 | // relay_url2 is the URL that will be rendered once loading.htm is loaded 65 | try { 66 | var scheme = hmtg.util.schemeURL(url); 67 | if(!scheme) { 68 | _browser.relay_url2 = $sce.trustAsResourceUrl('http://' + url); 69 | } else { 70 | _browser.relay_url2 = $sce.trustAsResourceUrl(url); 71 | } 72 | } catch(e) { 73 | _browser.relay_url2 = ''; 74 | } 75 | $rootScope.$broadcast(hmtgHelper.WM_BROWSER_URL); 76 | } 77 | 78 | this.append_history = function (url) { 79 | // remove existing one 80 | var i; 81 | for(i = 0; i < this.history.length; i++) { 82 | if(this.history[i] == url) { 83 | this.history.splice(i, 1); 84 | break; 85 | } 86 | } 87 | this.history.push(url); 88 | this.history_idx = this.history.length - 1; 89 | } 90 | 91 | this.turnon_fullscreen = function () { 92 | if(this.request_fullscreen) { 93 | this.request_fullscreen.call(this.container); 94 | } 95 | } 96 | 97 | this.turnoff_fullscreen = function () { 98 | hmtgHelper.exitFullScreen(true); 99 | this.is_fullscreen = false; 100 | this.is_passive_fullscreen = false; 101 | } 102 | 103 | } 104 | ]) 105 | 106 | ; 107 | -------------------------------------------------------------------------------- /joinnet/chat.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .service('chat', ['$translate', 'appSetting', 'hmtgHelper', 'hmtgAlert', '$rootScope', 10 | function($translate, appSetting, hmtgHelper, hmtgAlert, $rootScope) { 11 | var _chat = this; 12 | this.data = []; 13 | this.sendto_list = []; 14 | 15 | this.add_chat = function(source_ssrc, target_ssrc, settopflag, text, codepage, ts, date, is_chat_area_visible) { 16 | var data = _chat.data; 17 | var target = {}; 18 | target.text = hmtg.util.decodeUtf8(text); 19 | target.class_text = text.indexOf('>[To:') != -1 ? 'text-danger' : ''; 20 | target.src = source_ssrc; 21 | target.dst = target_ssrc; 22 | target.ts = ts; 23 | target.date = date; 24 | data.push(target); 25 | 26 | $rootScope.$broadcast(hmtgHelper.WM_UPDATE_CHAT, true); 27 | 28 | if(source_ssrc != hmtg.jnkernel._jn_ssrc_index()) { 29 | if($rootScope.nav_item != 'joinnet' || !is_chat_area_visible) { 30 | var item = {}; 31 | item['timeout'] = 30; 32 | item['text'] = hmtg.util.decodeUtf8(text); 33 | item['type'] = 'info'; 34 | item['click'] = function(index) { 35 | hmtgAlert.close_notification(item); 36 | hmtgHelper.inside_angular++; 37 | $rootScope.$broadcast(hmtgHelper.WM_SHOW_CHAT_AREA); 38 | clearTimeout(hmtgAlert.chat_alert_array[index].timeout_id); 39 | hmtgAlert.chat_alert_array.splice(index, 1); 40 | $rootScope.$broadcast(hmtgHelper.WM_UPDATE_ALERT); 41 | hmtgHelper.inside_angular--; 42 | }; 43 | item['item_click'] = function() { 44 | hmtgAlert.close_notification(item); 45 | $rootScope.$broadcast(hmtgHelper.WM_SHOW_CHAT_AREA); 46 | clearTimeout(item.timeout_id); 47 | var index = hmtgAlert.chat_alert_array.indexOf(item); 48 | if(index != -1) { 49 | hmtgAlert.chat_alert_array.splice(index, 1); 50 | $rootScope.$broadcast(hmtgHelper.WM_UPDATE_ALERT); 51 | } 52 | }; 53 | item['cancel'] = function() { 54 | hmtgAlert.close_notification(item); 55 | } 56 | 57 | hmtgAlert.update_chat_alert_item(item); 58 | item['notification'] = hmtgAlert.show_notification($translate.instant('IDS_APP_NAME'), item['text'], false, item['item_click']); 59 | } 60 | } else { 61 | hmtgAlert.clear_chat_alert_item(); 62 | } 63 | } 64 | 65 | this.reset = function() { 66 | _chat.data = []; 67 | _chat.sendto_list = []; 68 | $rootScope.$broadcast(hmtgHelper.WM_UPDATE_CHAT); 69 | } 70 | 71 | this.event_quit_session = function() { 72 | _chat.sendto_list = []; 73 | hmtgAlert.clear_chat_alert_item(); 74 | $rootScope.$broadcast(hmtgHelper.WM_UPDATE_CHAT); 75 | } 76 | 77 | } 78 | ]) 79 | 80 | ; 81 | -------------------------------------------------------------------------------- /joinnet/dt.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .service('sdt', ['$translate', 'appSetting', 'hmtgHelper', '$rootScope', 10 | function($translate, appSetting, hmtgHelper, $rootScope) { 11 | var _sdt = this; 12 | } 13 | ]) 14 | 15 | .service('rdc', ['$translate', 'appSetting', 'hmtgHelper', '$rootScope', 16 | function($translate, appSetting, hmtgHelper, $rootScope) { 17 | var _rdc = this; 18 | this.is_control = false; 19 | } 20 | ]) 21 | 22 | ; 23 | -------------------------------------------------------------------------------- /joinnet/mypicture.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .service('mypicture', ['$translate', 'appSetting', 'hmtgHelper', '$rootScope', 'hmtgSound', '$modal', 'joinnetHelper', 10 | function ($translate, appSetting, hmtgHelper, $rootScope, hmtgSound, $modal, joinnetHelper) { 11 | var _mypicture = this; 12 | this.data = null; 13 | this.type = -1; 14 | this.type_array = ['', 'image/bmp', 'image/gif', 'image/jpeg', 'image/png']; 15 | 16 | try { 17 | var hmd = typeof hmtg.util.localStorage['hmtg_mypicture_data'] === 'undefined' ? '' : JSON.parse(hmtg.util.localStorage['hmtg_mypicture_data']); 18 | if(typeof hmd === 'string') 19 | this.data = hmtg.util.str2array(hmd); 20 | else 21 | this.data = null; 22 | this.type = typeof hmtg.util.localStorage['hmtg_mypicture_type'] === 'undefined' ? -1 : JSON.parse(hmtg.util.localStorage['hmtg_mypicture_type']); 23 | if(!this.data || !this.data.length || this.data.length > hmtg.config.MAX_MYPICTURE_SIZE 24 | || this.type <= 0 || this.type >= this.type_array.length) 25 | this.data = null; 26 | } catch(e) { 27 | this.data = null; 28 | } 29 | 30 | this.net_init_finished = function () { 31 | if(hmtg.jnkernel._jn_iWorkMode() == hmtg.config.NORMAL && this.data) { 32 | hmtg.jnkernel.jn_command_UploadSelfPicture(this.type, this.data); 33 | } 34 | } 35 | } 36 | ]) 37 | 38 | ; 39 | -------------------------------------------------------------------------------- /joinnet/reconnect_name.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('joinnet') 8 | 9 | .service('reconnectName', ['$translate', 'appSetting', 'hmtgHelper', '$rootScope', 10 | function ($translate, appSetting, hmtgHelper, $rootScope) { 11 | var _reconnectName = this; 12 | this.check_permit_time_window = 60; // 1 hour 13 | this.permit_expiration_threshold = 3 * 60; // 3 hours 14 | this.reconnect_name_array = read_reconnect_name(); 15 | 16 | function read_reconnect_name() { 17 | var array = []; 18 | try { 19 | array = typeof hmtg.util.localStorage['hmtg_reconnect_name_array'] === 'undefined' ? [] : JSON.parse(hmtg.util.localStorage['hmtg_reconnect_name_array']); 20 | if(!hmtg.util.isArray(array)) return []; 21 | var i; 22 | var now = Date.now(); 23 | for(i = 0; i < array.length && i < 200; i++) { 24 | if(!array[i].tick || (now - array[i].tick) > _reconnectName.permit_expiration_threshold * 60 * 1000) { 25 | array = array.slice(0, i); 26 | break; 27 | } 28 | } 29 | } catch(e) { 30 | return []; 31 | } 32 | return array; 33 | } 34 | 35 | this.checkPermit = function () { 36 | var count = 0; 37 | var now = Date.now(); 38 | var i; 39 | var idx = -1; 40 | var array = _reconnectName.reconnect_name_array; 41 | for(i = 0; i < array.length; i++) { 42 | if(array[i].tick && (now - array[i].tick) < this.permit_expiration_threshold * 60 * 1000) { 43 | count++; 44 | idx = i; 45 | } 46 | } 47 | 48 | if(count == 0) return; 49 | 50 | // relay to the controller 51 | this.to_check_permit = true; 52 | this.to_check_permit_tick = now; 53 | $rootScope.selectTabReconnectName(); 54 | } 55 | 56 | function write_reconnect_name() { 57 | var array = _reconnectName.reconnect_name_array; 58 | var i; 59 | var now = Date.now(); 60 | for(i = 0; i < array.length && i < 200; i++) { 61 | if(!array[i].tick || (now - array[i].tick) > _reconnectName.permit_expiration_threshold * 60 * 1000) { 62 | array = _reconnectName.reconnect_name_array = array.slice(0, i); 63 | break; 64 | } 65 | } 66 | hmtg.util.localStorage['hmtg_reconnect_name_array'] = JSON.stringify(array); 67 | } 68 | 69 | this.update_reconnect_name = function (reconnect_name, real_name, ssrc, jnj) { 70 | var now = Date.now(); 71 | var item = { reconnect_name: reconnect_name, real_name: real_name, ssrc: ssrc, jnj: jnj, tick: now, time_str: (new Date()).toString().replace(/(GMT.*)/, "") }; 72 | var array = _reconnectName.reconnect_name_array = read_reconnect_name(); 73 | var i; 74 | for(i = 0; i < array.length; i++) { 75 | if(array[i].reconnect_name == reconnect_name) { 76 | array.splice(i, 1); 77 | break; 78 | } 79 | } 80 | array.unshift(item); 81 | write_reconnect_name(); 82 | $rootScope.$apply(); 83 | } 84 | 85 | this.remove_reconnect_name = function (reconnect_name) { 86 | var array = _reconnectName.reconnect_name_array = read_reconnect_name(); 87 | var i; 88 | for(i = 0; i < array.length; i++) { 89 | if(array[i].reconnect_name == reconnect_name) { 90 | array.splice(i, 1); 91 | break; 92 | } 93 | } 94 | write_reconnect_name(); 95 | $rootScope.$apply(); 96 | } 97 | 98 | this.reset_reconnect_name = function () { 99 | this.reconnect_name_array = []; 100 | write_reconnect_name(); 101 | } 102 | 103 | this.delete_reconnect_name = function (item) { 104 | var array = _reconnectName.reconnect_name_array = read_reconnect_name(); 105 | var i; 106 | for(i = 0; i < array.length; i++) { 107 | if(array[i].reconnect_name == item.reconnect_name) { 108 | array.splice(i, 1); 109 | write_reconnect_name(); 110 | break; 111 | } 112 | } 113 | } 114 | } 115 | ]) 116 | 117 | ; 118 | -------------------------------------------------------------------------------- /lang/translation-en.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | 4 | -------------------------------------------------------------------------------- /lazy_htm/_internal_option_test.htm: -------------------------------------------------------------------------------- 1 | 2 |

{{sound_info}}

3 |

{{audio_info}}

4 |

{{url_info}}

5 |

{{gum_info}}

6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_browser.htm: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 | 8 | 12 | 13 | 14 | 18 | 19 | 20 | 24 | 25 | 26 | 30 | 31 | 32 | 35 | 36 | 37 | 40 | 41 | {{'ID_BAD_HTTPS_URL' | translate}} 42 | 43 | 45 | 46 | 47 | 48 | 49 | 54 |
55 | 57 |
58 |
59 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_chat.htm: -------------------------------------------------------------------------------- 1 |
2 | 3 | 13 |
14 | 15 | 16 | 20 | 21 | 22 | 23 |
24 |
25 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_chat2.htm: -------------------------------------------------------------------------------- 1 |
2 | 3 | 13 |
14 | 15 | 16 | 20 | 21 | 22 | 23 |
24 |
25 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_image_bar.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 27 | 28 | {{'ID_LOADING_MARK' | translate}} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_jnr.htm: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

6 |

{{start_str()}}

7 |
8 |
9 |

10 |

{{duration}}

11 |
12 |
13 |

14 |

{{bandwidth}}

15 |
16 |
17 |
18 |
19 |

20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
{{jn.jnr_prop.title}}
{{jn.jnr_prop.category}}
{{jn.jnr_prop.keyword}}
{{jn.jnr_prop.abstrct}}
{{jn.jnr_prop.comment}}
{{jn.jnr_prop.registration}}
{{jn.jnr_prop.release_date}}
30 |
31 |
32 |
33 |

{{'ID_USER_RECORD' | translate}} ({{jn.jnr_prop.user_record_count}})

34 | {{jn.jnr_prop.user_record}} 35 |
36 |
37 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_playback.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 6 | 7 | 9 | 11 |
12 | 15 |
16 | 20 | 21 | 23 | 24 | 28 |
29 | 33 | 37 |
38 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_stat.htm: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 8 | 10 |
11 | 12 |
13 |
14 |
15 | 18 | {{snapshot_info}} 19 |
20 | 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /lazy_htm/joinnet_transcoding.htm: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
{{w.video_info}}
6 |
7 | 10 | 14 | 17 | 18 |
19 | 23 | 27 | 28 | 29 | 31 | 32 |
33 |
34 | 35 |
36 | 40 | 44 | 45 | 46 | 48 | 49 |
50 |
51 | 54 |
55 |
56 |
57 | -------------------------------------------------------------------------------- /lazy_htm/navitem_jnj.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

7 | 8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /lazy_htm/navitem_log.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | 6 | 8 | 10 | 11 | 15 | 16 | 17 | 22 | 23 |
24 |
25 | 27 |
28 |
29 |
30 | 31 | 32 | 33 | 35 | 37 | 38 | 42 | 43 | 44 | 48 | 49 |
50 |
51 | 53 |
54 |
55 |
56 |
57 | -------------------------------------------------------------------------------- /lazy_htm/navitem_missed_call.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 |
15 | 18 | {{item.name}}{{item.time_str}}{{calc_type(item)}}
25 |
26 |
27 | -------------------------------------------------------------------------------- /lazy_htm/navitem_prompt.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /lazy_htm/navitem_reconnect_name.htm: -------------------------------------------------------------------------------- 1 | 2 |

3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 22 | 23 | 24 | 25 | 26 | 27 |
16 | 17 | 18 | 21 | {{calc_real_name(item)}}{{item.time_str}}{{item.ssrc}}
28 |
29 |
30 | -------------------------------------------------------------------------------- /lazy_htm/option_msgr.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 | 6 |
7 |
8 | 11 |
12 |
13 | 16 |
17 |
18 | 19 |
20 |
21 |
22 | 25 |
26 |
27 | 30 |
31 |
32 | 35 |
36 |
37 | 40 |
41 |
42 |
43 | 46 |
47 |
48 | 51 |
52 |
53 | 56 |
57 |
58 | -------------------------------------------------------------------------------- /lazy_htm/option_mypicture.htm: -------------------------------------------------------------------------------- 1 | 2 | {{w.descr}} 3 |
4 | 5 | 9 | 13 |
14 | {{w.img_descr}} 15 |
16 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /lazy_htm/option_nativeapp.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /lazy_htm/option_score.htm: -------------------------------------------------------------------------------- 1 |
2 | 4 |
-------------------------------------------------------------------------------- /lazy_htm/option_webapp.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 | 6 |
7 |
8 | 11 |
12 |
13 | 16 |
17 |
18 |
19 | {{w.max_display_item}} 20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 | 28 |
29 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 | 40 | 42 | {{progress}} 43 | {{probe_result}} 44 |
45 |
46 | 47 |
48 | 49 |
50 |
51 | 54 |
55 |
56 | 57 |
58 | -------------------------------------------------------------------------------- /lazy_htm/option_webrtc.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 40 | 59 | 60 | 61 |
12 | 13 | 17 | 21 | 25 | 30 | 31 | 32 | 35 | 38 | 39 | 41 | 42 | {{item.server}} 43 | 44 | 45 |
46 | 47 | 48 |
49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 |
57 |
58 |
62 |
63 |
64 | -------------------------------------------------------------------------------- /lazy_js/joinnet_jnr.js: -------------------------------------------------------------------------------- 1 | angular.module('joinnet') 2 | .controller('JNRCtrl', ['$scope', 'playback', 'hmtgHelper', 'jnjContent', '$rootScope', '$modal', '$translate', 'hmtgAlert', 'JoinNet', 3 | function ($scope, playback, hmtgHelper, jnjContent, $rootScope, $modal, $translate, hmtgAlert, JoinNet) { 4 | $scope.jn = JoinNet; 5 | 6 | $scope.start_str = function () { 7 | return playback.start_str; 8 | } 9 | $scope.is_ready = function () { 10 | return playback.ready; 11 | } 12 | 13 | hmtgHelper.inside_angular++; 14 | if(playback.ready) init_stat(); 15 | hmtgHelper.inside_angular--; 16 | 17 | function init_stat() { 18 | var t = (((playback.end_tick - playback.start_tick) + 60000 - 1) / 60000) >> 0; 19 | $scope.duration = '' + t + $translate.instant('IDS_TIME_UNIT_MINUTE'); 20 | 21 | $scope.bandwidth = '' + playback.bandwidth + 'Kbps'; 22 | $scope.bandwidth = '' + hmtgHelper.number2gmk(playback.bandwidth * 1000) + 'bps'; 23 | if(!hmtgHelper.inside_angular) $scope.$digest(); 24 | } 25 | $scope.$on(hmtgHelper.WM_PLAYBACK_INIT_STAT, init_stat); 26 | 27 | $scope.$on(hmtgHelper.WM_UPDATE_PLAYBACK, function () { 28 | if(!hmtgHelper.inside_angular) $scope.$digest(); 29 | }); 30 | } 31 | ]) 32 | ; -------------------------------------------------------------------------------- /lazy_js/modal_change_jnr_password.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('ChangeJnrPasswordModalCtrl', ['$scope', '$modalInstance', '$translate', 'hmtgHelper', 3 | function($scope, $modalInstance, $translate, hmtgHelper) { 4 | $scope.w = {}; 5 | $scope.w.password1 = $scope.w.password2 = ''; 6 | $scope.w.type = $scope.set_password_only ? 0 : 1; 7 | if($scope.w.type) { 8 | $scope.w.item = $scope.item; 9 | $scope.w.encrypted = !!($scope.item.flag & 0x40000000); 10 | } 11 | 12 | $scope.ok = function() { 13 | var password0 = ''; 14 | if($scope.w.type) { 15 | if($scope.w.encrypted) { 16 | if(!$scope.w.password0) return; 17 | if($scope.w.password1 == $scope.w.password0) return; 18 | 19 | password0 = hmtg.util.encodeUtf8($scope.w.password0); 20 | if(password0.length >= hmtg.config.MAX_PASSWORD) { 21 | hmtgHelper.MessageBox($translate.instant('IDS_PASSWORD_TOO_LONG'), 0); 22 | return; 23 | } 24 | } 25 | } 26 | if($scope.w.password1 != $scope.w.password2) return; 27 | var password = hmtg.util.encodeUtf8($scope.w.password1); 28 | if(password.length >= hmtg.config.MAX_PASSWORD) { 29 | hmtgHelper.MessageBox($translate.instant('IDS_PASSWORD_TOO_LONG'), 0); 30 | return; 31 | } 32 | $modalInstance.close({ 33 | password0: password0, 34 | password: password 35 | }); 36 | }; 37 | 38 | $scope.cancel = function() { 39 | $modalInstance.dismiss('cancel'); 40 | }; 41 | } 42 | ]) 43 | 44 | ; -------------------------------------------------------------------------------- /lazy_js/modal_download_complete.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('DownloadCompleteModalCtrl', ['$scope', '$modalInstance', '$translate', 'hmtgHelper', 3 | 'msgrHelper', 'jnagentDlg', 'appSetting', 'hmtgAlert', 4 | function($scope, $modalInstance, $translate, hmtgHelper, msgrHelper, jnagentDlg, appSetting, 5 | hmtgAlert) { 6 | $scope.w = {}; 7 | $scope.w.item = $scope.downloadC_item; 8 | 9 | $scope.ok = function() { 10 | try { 11 | if(hmtgHelper.isiOS) { 12 | hmtgHelper.inside_angular++; 13 | hmtgAlert.add_blob_download_item(new Blob([$scope.downloadC_data]), hmtg.util.decodeUtf8($scope.w.item.tick_str + ' ' + $scope.w.item.title + '.jnr')); 14 | hmtgHelper.inside_angular--; 15 | } else { 16 | hmtgHelper.save_file(new Blob([$scope.downloadC_data]), hmtg.util.decodeUtf8($scope.w.item.tick_str + ' ' + $scope.w.item.title + '.jnr')); 17 | } 18 | } catch(e) { 19 | } 20 | $scope.downloadC_data = null; 21 | $modalInstance.close(); 22 | }; 23 | 24 | $scope.cancel = function() { 25 | $modalInstance.dismiss('cancel'); 26 | }; 27 | 28 | } 29 | ]) 30 | 31 | ; -------------------------------------------------------------------------------- /lazy_js/modal_edit_profile.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('EditProfileModalCtrl', ['$scope', '$modalInstance', '$translate', 'hmtgHelper', '$sce', 'msgrHelper', 3 | function($scope, $modalInstance, $translate, hmtgHelper, $sce, msgrHelper) { 4 | $scope.w = {}; 5 | var param = $scope.editp_param; 6 | $scope.w.is_mmc = param._mmc_messenger(); 7 | $scope.subtitle = msgrHelper.CalcOfficeText1($translate.instant, param); 8 | if($scope.w.is_mmc) { 9 | $scope.w.url2 = $sce.trustAsResourceUrl($scope.editp_url); 10 | } else { 11 | $scope.w.visit_url = 'https://' + param._jnj_ip(); 12 | if(param._port() != 443) { 13 | $scope.w.visit_url += ':' + param._port() 14 | } 15 | $scope.w.visit_url += '/weboffice_' + hmtg.util.decodeUtf8(param._userid()) + '.jnj?web=1'; 16 | $scope.w.username = hmtg.util.decodeUtf8(param._username()); 17 | $scope.w.email = hmtg.util.decodeUtf8(param._email()); 18 | $scope.w.password0 = ''; 19 | $scope.w.password1 = $scope.w.password2 = hmtg.util.decodeUtf8(param._password()); 20 | $scope.w.deny_msg = !!param._deny_message(); 21 | } 22 | 23 | $scope.style_height2 = { 'height': Math.max(200, (hmtgHelper.view_port_height - 195)) + 'px' }; 24 | $scope.style_height3 = { 'max-height': Math.max(240, (hmtgHelper.view_port_height - 185)) + 'px' }; 25 | 26 | $scope.copy = function() { 27 | var target = document.getElementById("edit_profile_url"); 28 | if(!target) { 29 | return; 30 | } 31 | hmtg.util.selectText(target); 32 | try { 33 | document.execCommand('copy'); 34 | } catch(e) { 35 | } 36 | } 37 | 38 | $scope.open_url = function() { 39 | window.open($scope.w.url2, hmtg.util.app_id + 'edit_profile').focus(); 40 | } 41 | 42 | $scope.ok = function() { 43 | if($scope.w.password1 != $scope.w.password2) { 44 | hmtgHelper.MessageBox($translate.instant('IDS_PASSWORD_NOT_MATCH'), 0); 45 | return; 46 | } 47 | 48 | var username = hmtg.util.encodeUtf8($scope.w.username); 49 | if(username.length >= hmtg.config.MAX_USERNAME) { 50 | hmtgHelper.MessageBox($translate.instant('IDS_USERNAME_TOO_LONG'), 0); 51 | return; 52 | } 53 | if(!username.length) { 54 | hmtgHelper.MessageBox($translate.instant('IDS_EMPTY_USERNAME'), 0); 55 | return; 56 | } 57 | 58 | var email = hmtg.util.encodeUtf8($scope.w.email); 59 | if(email.length >= hmtg.config.MAX_EMAIL) { 60 | hmtgHelper.MessageBox($translate.instant('IDS_EMAIL_TOO_LONG'), 0); 61 | return; 62 | } 63 | 64 | var password = hmtg.util.encodeUtf8($scope.w.password1); 65 | if(password.length >= hmtg.config.MAX_PASSWORD) { 66 | hmtgHelper.MessageBox($translate.instant('IDS_PASSWORD_TOO_LONG'), 0); 67 | return; 68 | } 69 | 70 | var password0 = hmtg.util.encodeUtf8($scope.w.password0); 71 | if(password0 != param._password()) { 72 | hmtgHelper.MessageBox($translate.instant('IDS_INVALID_OLD_PASSWORD'), 0); 73 | return; 74 | } 75 | 76 | var name_changed = 0; 77 | if(username != param._username()) { 78 | name_changed = 1; 79 | } 80 | 81 | if(username != param._username() 82 | || email != param._email() 83 | || password != param._password() 84 | || $scope.w.deny_msg != !!param._deny_message() 85 | ) { 86 | param._username(username); 87 | param._email(email); 88 | param._password(password); 89 | param._deny_message($scope.w.deny_msg); 90 | hmtg.jmkernel.jm_command_WriteUserProfile(param); 91 | } 92 | 93 | if(name_changed) { 94 | hmtg.jmkernel.jm_command_PgcUsernameChange(param, param._userid()); 95 | } 96 | if(password != param._password()) { 97 | hmtg.jmkernel.jm_command_UpdateWebOfficeProfile(param); 98 | hmtg.jmkernel.jm_command_WriteWBL(); 99 | } 100 | 101 | $modalInstance.close(); 102 | }; 103 | 104 | $scope.cancel = function() { 105 | $modalInstance.dismiss('cancel'); 106 | }; 107 | } 108 | ]) 109 | 110 | ; -------------------------------------------------------------------------------- /lazy_js/modal_jeditor.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('JeditorModalCtrl', ['$scope', '$modalInstance', '$translate', 'hmtgHelper', 3 | function($scope, $modalInstance, $translate, hmtgHelper) { 4 | $scope.w = {}; 5 | $scope.w.item = $scope.item; 6 | $scope.w.start = $scope.w.end = '00:00:00'; 7 | var cmd0 = $scope.w.text = '#NTT=' + hmtg.util.decodeUtf8($scope.title) 8 | + '\n#CUT=00:00:00,00:00:00' 9 | + '\n#CTA=00:00:00,00:00:00' 10 | + '\n#CTA#=00:00:00,00:00:00' 11 | + '\n#CTV=00:00:00,00:00:00' 12 | + '\n#CTV#=00:00:00,00:00:00' 13 | + '\n#CTT=00:00:00,00:00:00' 14 | + '\n#CTP=00:00:00,00:00:00'; 15 | 16 | $scope.ok = function() { 17 | var c = ''; 18 | var w = $scope.w; 19 | if(w.cut_all) { 20 | c += 'CUT=' + w.start + ',' + w.end + '\n'; 21 | } 22 | if(w.cut_video) { 23 | c += 'CVD\n'; 24 | } 25 | if(w.keep_v) { 26 | c += 'TCV\n'; 27 | } 28 | if(w.keep_av) { 29 | c += 'CAV\n'; 30 | } 31 | if(w.cut_text) { 32 | c += 'CAT\n'; 33 | } 34 | if(w.cut_url) { 35 | c += 'BAU\n'; 36 | } 37 | if(w.text) { 38 | c += w.text; 39 | } 40 | if(c == cmd0) return; 41 | if(!c) return; 42 | if(c.length > 30000) return; 43 | $modalInstance.close(hmtg.util.encodeUtf8(c)); 44 | }; 45 | 46 | $scope.cancel = function() { 47 | $modalInstance.dismiss('cancel'); 48 | }; 49 | } 50 | ]) 51 | 52 | ; -------------------------------------------------------------------------------- /lazy_js/modal_move_office.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('MoveOfficeModalCtrl', ['$scope', '$modalInstance', '$translate', 'hmtgHelper', 'msgrHelper', 'jnagentDlg', 'appSetting', 3 | function($scope, $modalInstance, $translate, hmtgHelper, msgrHelper, jnagentDlg, appSetting) { 4 | $scope.as = appSetting; 5 | $scope.w = jnagentDlg; 6 | 7 | $scope.style_height = { 'max-height': Math.max(240, (hmtgHelper.view_port_height - 190)) + 'px' }; 8 | 9 | $scope.move_up = function(item) { 10 | var idx = jnagentDlg.data.indexOf(item); 11 | if(idx == -1) return; 12 | if(idx == 0) return; 13 | 14 | jnagentDlg.data.splice(idx, 1) 15 | jnagentDlg.data.splice(idx - 1, 0, item); 16 | } 17 | 18 | $scope.move_down = function(item) { 19 | var idx = jnagentDlg.data.indexOf(item); 20 | if(idx == -1) return; 21 | if(idx == jnagentDlg.data.length - 1) return; 22 | 23 | jnagentDlg.data.splice(idx, 1) 24 | jnagentDlg.data.splice(idx + 1, 0, item); 25 | } 26 | 27 | $scope.cancel = function() { 28 | $modalInstance.dismiss('cancel'); 29 | }; 30 | 31 | } 32 | ]) 33 | 34 | ; -------------------------------------------------------------------------------- /lazy_js/modal_msgr_signin.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('MsgrSigninModalCtrl', ['$rootScope', '$scope', '$modalInstance', '$modal', '$translate', 'Msgr', 'msgrHelper', 'appSetting', 'hmtgSound', 'hmtgHelper', 3 | function ($rootScope, $scope, $modalInstance, $modal, $translate, Msgr, msgrHelper, appSetting, hmtgSound, hmtgHelper) { 4 | $scope.w = {}; 5 | $scope.w.remember_passwd = false; 6 | $scope.w.password = ''; 7 | $scope.w.bad_https = false; 8 | $scope.w.is_reconnect = $scope.reconnect_flag ? true : false; 9 | $scope.w.is_password_error = $scope.password_error ? true : false; 10 | if($scope.reconnect_flag) { 11 | $scope.w.remember_passwd = $scope.to_remember_passwd; 12 | $scope.w.password = hmtg.util.decodeUtf8($scope.reconnect_password); 13 | $scope.title = $translate.instant('IDS_CONNECTION_STATUS_PREPARE_RECONNECT'); 14 | } else { 15 | $scope.title = $translate.instant('IDD_DIALOG_SIGNIN'); 16 | } 17 | 18 | var LS_list = hmtg.util.localStorage['hmtg_msgr_homepage_list']; 19 | var list = []; 20 | if(typeof LS_list == 'string') { 21 | var a_list = hmtg.util.parseJSON(LS_list); 22 | if(a_list === 'undefined') a_list = []; 23 | if(hmtg.util.isArray(a_list)) { 24 | list = a_list.slice(0, 10); 25 | } 26 | } 27 | $scope.hmlist = []; 28 | var i; 29 | for(i = 0; i < list.length; i++) { 30 | if(typeof list[i] == 'string') $scope.hmlist.push({ name: list[i] }); 31 | } 32 | 33 | var homepage_value = list[0] ? list[0] : ""; 34 | 35 | var LS_list = hmtg.util.localStorage['hmtg_msgr_userid_list']; 36 | var list = []; 37 | if(typeof LS_list == 'string') { 38 | var a_list = hmtg.util.parseJSON(LS_list); 39 | if(a_list === 'undefined') a_list = []; 40 | if(hmtg.util.isArray(a_list)) { 41 | list = a_list.slice(0, 10); 42 | } 43 | } 44 | $scope.idlist = []; 45 | var i; 46 | for(i = 0; i < list.length; i++) { 47 | if(typeof list[i] == 'string') $scope.idlist.push({ name: list[i] }); 48 | } 49 | 50 | var userid_value = list[0] ? list[0] : ""; 51 | if($scope.m_homepage && $scope.m_userid) { 52 | homepage_value = $scope.m_homepage; 53 | userid_value = $scope.m_userid; 54 | } 55 | $scope.homepage_placeholder = homepage_value ? '' : $translate.instant('IDC_STATIC_1_HOMEPAGE'); 56 | $scope.userid_placeholder = userid_value ? '' : $translate.instant('IDS_COL_USERID'); 57 | 58 | $scope.w.initial_status = $scope.initial_status || hmtg.config.ONLINE_STATUS_ONLINE; 59 | $scope.w.guest = false; 60 | $scope.w.homepage = homepage_value; 61 | $scope.w.userid = userid_value; 62 | 63 | $scope.$watch('w.homepage', function () { 64 | $scope.w.bad_https = false; 65 | if($scope.w.homepage) { 66 | var h = $scope.w.homepage.toLowerCase(); 67 | if(h.length >= 8) { 68 | if(h.indexOf('https://') != 0) 69 | $scope.w.bad_https = true; 70 | } else { 71 | if('https://'.indexOf(h) != 0) 72 | $scope.w.bad_https = true; 73 | } 74 | } 75 | }); 76 | 77 | $scope.userstatus2string = function (status) { 78 | return $translate.instant(msgrHelper.userstatus2id(status, 0, 1)); 79 | } 80 | 81 | $scope.ok = function () { 82 | if(!$scope.w.homepage) return; 83 | if(!$scope.w.userid && !$scope.w.guest) return; 84 | var hp = $scope.w.homepage; 85 | var scheme = hmtg.util.schemeURL(hp); 86 | if(!scheme) { 87 | hp = ($rootScope.is_secure ? 'https://' : 'http://') + hp; 88 | } 89 | if($rootScope.is_secure && appSetting.auto_https && hp.toLowerCase().indexOf('http://') == 0) { 90 | var old = hp; 91 | hp = 'https://' + hp.slice(7); 92 | hmtgHelper.inside_angular++; 93 | hmtgSound.ShowInfoPrompt(function () { 94 | return $translate.instant('ID_HTTP_TO_HTTPS').replace('#http#', old).replace('#https#', hp); 95 | }, 10, false); 96 | hmtgHelper.inside_angular--; 97 | } 98 | $modalInstance.close({ 99 | homepage: hmtg.util.encodeUtf8Ex(hp, 100), 100 | guest: $scope.w.guest, 101 | userid: hmtg.util.encodeUtf8Ex($scope.w.userid, hmtg.config.MAX_USERID), 102 | password: hmtg.util.encodeUtf8Ex($scope.w.password, hmtg.config.MAX_PASSWORD), 103 | initial_status: $scope.w.initial_status, 104 | remember_passwd: $scope.w.remember_passwd 105 | }); 106 | }; 107 | 108 | $scope.cancel = function () { 109 | $modalInstance.dismiss('cancel'); 110 | }; 111 | } 112 | ]) 113 | 114 | ; 115 | -------------------------------------------------------------------------------- /lazy_js/modal_rename.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('RenameModalCtrl', ['$scope', '$modalInstance', 'hmtgHelper', '$translate', 3 | function($scope, $modalInstance, hmtgHelper, $translate) { 4 | $scope.w = {}; 5 | var old = $scope.w.new_name = $scope.new_name; 6 | 7 | setTimeout(function() { 8 | var elem = document.getElementById("new_name"); 9 | if(elem) elem.focus(); 10 | }, 100); 11 | 12 | 13 | $scope.onkeypress = function(e) { 14 | if(e.keyCode == 13) { 15 | e.stopPropagation(); 16 | e.preventDefault(); 17 | $scope.ok(); 18 | return; 19 | } 20 | } 21 | 22 | $scope.ok = function() { 23 | if(old == $scope.w.new_name) return; 24 | var new_name = hmtg.util.encodeUtf8($scope.w.new_name); 25 | var error_id; 26 | if($scope.func) { 27 | if(typeof $scope.func === 'function') { 28 | error_id = $scope.func(new_name); 29 | } else if($scope.func === 'pm' 30 | || $scope.func === 'rename_pgc' 31 | || $scope.func === 'rename_office' 32 | || $scope.func === 'set_group' 33 | || $scope.func === 'change_title' 34 | ) { 35 | if(new_name.length >= hmtg.config.MAX_USERNAME) error_id = 'IDS_PGC_NAME_TOO_LONG'; 36 | } else if($scope.func === 'new_contact_group') { 37 | if(!new_name) return; 38 | if(new_name.length >= hmtg.config.MAX_USERNAME) { 39 | error_id = 'IDS_PGC_NAME_TOO_LONG'; 40 | } else { 41 | var param = $scope.context[0]; 42 | var a = param._m_pContactGroupArray(); 43 | if(a && a.length) { 44 | var i; 45 | for(i = 0; i < a.length; i++) { 46 | var group = a[i]; 47 | if(group.m_szGroupName == new_name) { 48 | error_id = 'IDS_GROUP_NAME_EXIST'; 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | } else if($scope.func === 'rename_contact_group') { 55 | if(!new_name) return; 56 | if(new_name.length >= hmtg.config.MAX_USERNAME) { 57 | error_id = 'IDS_PGC_NAME_TOO_LONG'; 58 | } else { 59 | var param = $scope.context[0]; 60 | var group0 = $scope.context[1]; 61 | var a = param._m_pContactGroupArray(); 62 | if(a && a.length) { 63 | var i; 64 | for(i = 0; i < a.length; i++) { 65 | var group = a[i]; 66 | if(group == group0) continue; 67 | if(group.m_szGroupName == new_name) { 68 | error_id = 'IDS_GROUP_NAME_EXIST'; 69 | break; 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | if(error_id) { 77 | hmtgHelper.MessageBox($translate.instant(error_id), 0); 78 | return; 79 | } 80 | $modalInstance.close({ 81 | new_name: new_name 82 | }); 83 | }; 84 | 85 | $scope.cancel = function() { 86 | $modalInstance.dismiss('cancel'); 87 | }; 88 | } 89 | ]) 90 | 91 | ; -------------------------------------------------------------------------------- /lazy_js/modal_short_message.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('ShortMessageModalCtrl', ['$scope', '$modalInstance', 3 | function ($scope, $modalInstance) { 4 | $scope.w = {}; 5 | 6 | setTimeout(function () { 7 | var elem = document.getElementById("message_text"); 8 | if(elem) elem.focus(); 9 | }, 100); 10 | 11 | $scope.ok = function () { 12 | if(!$scope.w.text) return; 13 | var text = hmtg.util.encodeUtf8($scope.w.text); 14 | if(text.length >= 500) return; 15 | $modalInstance.close({ 16 | text: text 17 | }); 18 | }; 19 | 20 | $scope.cancel = function () { 21 | $modalInstance.dismiss('cancel'); 22 | }; 23 | } 24 | ]) 25 | 26 | ; -------------------------------------------------------------------------------- /lazy_js/modal_style.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('StyleModalCtrl', ['$scope', '$modalInstance', 'imDlg', '$translate', 'appSetting', 'board', 'imStyle', 3 | function($scope, $modalInstance, imDlg, $translate, appSetting, board, imStyle) { 4 | $scope.as = appSetting; 5 | $scope.bd = board; 6 | $scope.w = {}; 7 | 8 | var im = $scope.im; 9 | var param = im.m_param; 10 | var old_style = param._im_style_flag(); 11 | param._imstyle(imStyle.style2object(param._im_style_flag())); 12 | $scope.st = param._imstyle(); 13 | 14 | var tmp = param._ngstyle(); 15 | if(tmp.color) { 16 | $scope.w.color = tmp.color; 17 | } else { 18 | $scope.w.color = '#000000'; 19 | } 20 | 21 | $scope.style_color = function(idx) { 22 | return { 'color': board.colors[idx], 'background-color': board.colors[idx] } 23 | } 24 | $scope.choose_color = function(idx) { 25 | update_color(board.colors[idx]); 26 | } 27 | 28 | $scope.$watch('w.color', function(newValue, oldValue) { 29 | if(typeof newValue !== 'string') return; 30 | update_color(newValue); 31 | }); 32 | 33 | function update_color(color) { 34 | var value = parseInt(color.slice(1), 16); 35 | if(isNaN(value)) value = 0x000000; 36 | var r = (value >> 16) & 0xff; 37 | var g = (value >> 8) & 0xff; 38 | var b = value & 0xff; 39 | $scope.st.has_color = true; 40 | $scope.st.red = r; 41 | $scope.st.green = g; 42 | $scope.st.blue = b; 43 | update_style(); 44 | } 45 | 46 | $scope.$watch('st.is_bold', update_style); 47 | $scope.$watch('st.is_italic', update_style); 48 | $scope.$watch('st.is_underline', update_style); 49 | $scope.$watch('st.is_strike', update_style); 50 | 51 | function update_style() { 52 | var style = imStyle.object2style($scope.st); 53 | param._im_style_flag(style); 54 | param._ngclass(imStyle.ngclass(style)); 55 | param._ngstyle(imStyle.ngstyle(style)); 56 | } 57 | 58 | $scope.ok = function() { 59 | var new_style = param._im_style_flag(); 60 | if(new_style != old_style) { 61 | hmtg.jmkernel.jm_command_TouchClientInfo(param); 62 | } 63 | $modalInstance.close(); 64 | }; 65 | 66 | $scope.cancel = function() { 67 | param._im_style_flag(old_style); 68 | param._ngclass(imStyle.ngclass(old_style)); 69 | param._ngstyle(imStyle.ngstyle(old_style)); 70 | $modalInstance.dismiss('cancel'); 71 | }; 72 | } 73 | ]) 74 | 75 | ; -------------------------------------------------------------------------------- /lazy_js/modal_view_record.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('ViewRecordModalCtrl', ['$scope', '$modalInstance', '$translate', 'hmtgHelper', 'msgrHelper', '$sce', 'appSetting', 3 | function($scope, $modalInstance, $translate, hmtgHelper, msgrHelper, $sce, appSetting) { 4 | $scope.as = appSetting; 5 | $scope.w = {}; 6 | $scope.w.item_list = []; 7 | $scope.w.sort_target = 1; 8 | $scope.ascending = true; 9 | 10 | var data = $scope.data; 11 | $scope.w.item = $scope.item; 12 | $scope.w.is_mmc = $scope.param._mmc_messenger(); 13 | 14 | $scope.style_height = { 'max-height': Math.max(240, (hmtgHelper.view_port_height - 190)) + 'px' }; 15 | $scope.style_height2 = { 'height': Math.max(200, (hmtgHelper.view_port_height - 195)) + 'px' }; 16 | $scope.style_height3 = { 'max-height': Math.max(240, (hmtgHelper.view_port_height - 185)) + 'px' }; 17 | 18 | function calcTotalTimeStr(value) { 19 | if(value >= 3600 * 24) { 20 | return ((value / 3600 / 24) >>> 0) + ' ' + $translate.instant('IDS_TIME_UNIT_DAY'); 21 | } else if(value >= 3600) { 22 | return ((value / 3600) >>> 0) + ' ' + $translate.instant('IDS_TIME_UNIT_HOUR'); 23 | } else if(value >= 60) { 24 | return ((value / 60) >>> 0) + ' ' + $translate.instant('IDS_TIME_UNIT_MINUTE'); 25 | } else { 26 | return Math.max(1, (value >>> 0)) + ' ' + $translate.instant('IDS_TIME_UNIT_SECOND'); 27 | } 28 | } 29 | function init_list() { 30 | while(data.length >= 16) { 31 | var r = hmtg.jmkernel.jm_command_ParseViewRecord(data); 32 | if(!r) break; 33 | var item = {}; 34 | item.player_name = hmtg.util.decodeUtf8(r[1]); 35 | item.view_count = r[2]; 36 | item.total_time = r[3]; 37 | item.total_time_str = calcTotalTimeStr(r[3]); 38 | item.last_playtime = msgrHelper.get_timestring_im3(r[4]); 39 | item.last_playtime_str = msgrHelper.get_timestring_im3(r[4]); 40 | 41 | 42 | var a = $scope.w.item_list; 43 | a.push(item); 44 | data = data.slice(r[0] + 16); 45 | } 46 | 47 | $scope.sort(); 48 | } 49 | 50 | $scope.compare = function(item1, item2) { 51 | var result = $scope.compare0(item1, item2); 52 | if($scope.w.ascending) return -result; 53 | return result; 54 | } 55 | 56 | $scope.compare0 = function(item1, item2) { 57 | var result; 58 | switch($scope.w.sort_target) { 59 | case 1: 60 | if(item1.player_name < item2.player_name) return -1; 61 | if(item1.player_name > item2.player_name) return 1; 62 | break; 63 | case 2: 64 | result = item1.view_count - item2.view_count; 65 | if(result != 0) return result; 66 | if(!item1.view_count) { 67 | if((item1.flag & 0x20000000) && !(item2.flag & 0x20000000)) return 1; 68 | if(!(item1.flag & 0x20000000) && (item2.flag & 0x20000000)) return -1; 69 | } 70 | break; 71 | case 3: 72 | result = item1.total_time - item2.total_time; 73 | if(result != 0) return result; 74 | break; 75 | case 4: 76 | result = item1.last_playtime - item2.last_playtime; 77 | if(result != 0) return result; 78 | break; 79 | default: 80 | return -1; 81 | } 82 | return 0; 83 | } 84 | 85 | $scope.sort = function() { 86 | // insertion sorting, simple and good for nearly sorted array 87 | var i, j; 88 | for(i = 1; i < $scope.w.item_list.length; i++) { 89 | var x = $scope.w.item_list[i]; 90 | j = i; 91 | while(j > 0 && $scope.compare($scope.w.item_list[j - 1], x) > 0) { 92 | $scope.w.item_list[j] = $scope.w.item_list[j - 1]; 93 | j--; 94 | } 95 | if(i != j) $scope.w.item_list[j] = x; 96 | } 97 | } 98 | 99 | $scope.resort = function(sort_target) { 100 | if($scope.w.sort_target == sort_target) { 101 | $scope.w.ascending = !$scope.w.ascending; 102 | $scope.w.item_list.reverse(); 103 | } else { 104 | $scope.w.sort_target = sort_target; 105 | $scope.sort(); 106 | } 107 | } 108 | 109 | $scope.cancel = function() { 110 | $modalInstance.dismiss('cancel'); 111 | }; 112 | 113 | $scope.open_url = function() { 114 | window.open($scope.w.url2, hmtg.util.app_id + 'view_record').focus(); 115 | } 116 | 117 | if($scope.w.is_mmc) { 118 | $scope.w.url2 = $sce.trustAsResourceUrl(data); 119 | } else { 120 | init_list(); 121 | } 122 | } 123 | ]) 124 | 125 | ; -------------------------------------------------------------------------------- /lazy_js/navitem_jnj.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('JnjSourceCtrl', ['$scope', 'jnjSource', 'jnjContent', 'JoinNet', '$rootScope', 'hmtgHelper', 'appSetting', 3 | 'hmtgSound', '$sce', 'msgrHelper', 'joinnetHelper', '$translate', 4 | function($scope, jnjSource, jnjContent, JoinNet, $rootScope, hmtgHelper, appSetting, hmtgSound, $sce, msgrHelper, 5 | joinnetHelper, $translate) { 6 | $scope.jnj_source = ''; 7 | function adjust_height() { 8 | $scope.style_height1 = { 'height': (hmtgHelper.view_port_height * 0.7) + 'px' }; 9 | if(!hmtgHelper.inside_angular) $scope.$digest(); 10 | } 11 | hmtgHelper.inside_angular++; 12 | adjust_height(); 13 | hmtgHelper.inside_angular--; 14 | $scope.$on(hmtgHelper.WM_HEIGHT_CHANGED, adjust_height); 15 | 16 | $scope.$on(hmtgHelper.WM_OPEN_JNJ, function(event, jnj) { 17 | using_last_jnj = false; 18 | $scope.jnj_source = hmtg.util.decodeUtf8(jnj); 19 | }); 20 | 21 | $scope.$watch('jnj_source', function() { 22 | $scope.is_valid_jnj = $scope.jnj_source && jnjContent.validateJnj($scope.jnj_source); 23 | $scope.jnj_can_connect = $scope.is_valid_jnj || $scope.jnj_source.match(/^https?:\/\/.+/i); 24 | }); 25 | 26 | var using_last_jnj = false; 27 | $scope.connect = function() { 28 | if(!$scope.jnj_can_connect) return; 29 | 30 | hmtgSound.turnOnAudio(); 31 | 32 | hmtgHelper.inside_angular++; 33 | if($scope.is_valid_jnj) { 34 | if(hmtg.jmkernel.jm_callback_LaunchJoinNet) hmtg.jmkernel.jm_callback_LaunchJoinNet(hmtg.util.encodeUtf8($scope.jnj_source)); 35 | } else { 36 | joinnetHelper.connect_url($scope.jnj_source); 37 | } 38 | hmtgHelper.inside_angular--; 39 | } 40 | $scope.load_last_jnj = function() { 41 | if($scope.jnj_source) { 42 | hmtgHelper.OKCancelMessageBox($translate.instant('ID_LOAD_LAST_JNJ_PROMPT'), 0, ok); 43 | } else { 44 | ok(); 45 | } 46 | function ok() { 47 | var lj = hmtg.util.localStorage['last_jnj']; 48 | if(typeof lj === 'string') 49 | $scope.jnj_source = hmtg.util.decodeUtf8(lj); 50 | } 51 | } 52 | $scope.can_load = function() { 53 | return hmtg.util.localStorage['last_jnj'] && typeof hmtg.util.localStorage['last_jnj'] === 'string'; 54 | } 55 | 56 | $scope.clear_last_jnj = function() { 57 | if($scope.can_load()) { 58 | hmtgHelper.OKCancelMessageBox($translate.instant('ID_DELETE_LAST_JNJ_PROMPT'), 0, ok); 59 | } 60 | function ok() { 61 | hmtg.util.localStorage.removeItem('last_jnj'); 62 | } 63 | } 64 | 65 | $scope.reset = function() { 66 | if($scope.jnj_source) { 67 | hmtgHelper.OKCancelMessageBox($translate.instant('ID_RESET_JNJ_PROMPT'), 0, ok); 68 | } 69 | function ok() { 70 | $scope.jnj_source = ''; 71 | } 72 | } 73 | 74 | $scope.calc_url = function(jnj) { 75 | if(!jnj) return ''; 76 | return location.href.split('?')[0].split('#')[0] + '?jnj=' + hmtg.util.encode64_url(hmtg.util.encodeUtf8(jnj)); 77 | } 78 | 79 | } 80 | ]) 81 | ; 82 | -------------------------------------------------------------------------------- /lazy_js/navitem_missed_call.js: -------------------------------------------------------------------------------- 1 | angular.module('msgr') 2 | .controller('MissedCallCtrl', ['$scope', 'hmtgHelper', '$rootScope', '$translate', 'missedCall', 'hmtgAlert', 3 | function($scope, hmtgHelper, $rootScope, $translate, missedCall, hmtgAlert) { 4 | $scope.w = missedCall; 5 | 6 | $scope.calc_type = function(item) { 7 | return $translate.instant(item.tid); 8 | } 9 | 10 | $scope.remove = function(item) { 11 | missedCall.delete_missed_call(item); 12 | if(!missedCall.missed_call_array.length) { 13 | if($rootScope.hmtg_show_msgr) { 14 | $rootScope.nav_item = 'msgr'; 15 | $rootScope.tabs[0].active = true; 16 | } else { 17 | $rootScope.nav_item = 'joinnet'; 18 | $rootScope.tabs[2].active = true; 19 | } 20 | } 21 | } 22 | 23 | hmtgHelper.inside_angular++; 24 | if(missedCall.missed_call_array.length && missedCall.to_check_missed_call) { 25 | missedCall.to_check_missed_call = false; 26 | 27 | var item = {}; 28 | item['timeout'] = 30; 29 | item['update'] = function() { 30 | return $translate.instant('IDS_SHOW_MISSED_CALLS') 31 | }; 32 | item['text'] = item['update'](); 33 | item['type'] = 'info'; 34 | item['click'] = function(index) { 35 | hmtgHelper.inside_angular++; 36 | hmtgAlert.click_link(index); 37 | $rootScope.nav_item = 'missed_call'; 38 | $rootScope.tabs[4].active = true; 39 | $rootScope.selectTabMissedCall(); 40 | hmtgHelper.inside_angular--; 41 | }; 42 | 43 | hmtgAlert.add_link_item(item); 44 | } 45 | hmtgHelper.inside_angular--; 46 | } 47 | ]) 48 | ; -------------------------------------------------------------------------------- /lazy_js/navitem_prompt.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('PromptCtrl', ['$scope', 'jnjSource', 'jnjContent', 'JoinNet', '$rootScope', 'hmtgHelper', 'appSetting', 'hmtgSound', '$sce', 3 | function($scope, jnjSource, jnjContent, JoinNet, $rootScope, hmtgHelper, appSetting, hmtgSound, $sce) { 4 | $scope.as = appSetting; 5 | $scope.plain_jnj = $rootScope.jnj_source; 6 | $scope.blob = null; 7 | if(window.URL && $rootScope.jnj_source) { 8 | $scope.blob = new Blob([$rootScope.jnj_source], { type: hmtgHelper.isiOS ? 'text/plain' : 'application/joinnet' }); 9 | $scope.jnj_href = window.URL.createObjectURL($scope.blob); 10 | //hmtg.util.log($scope.jnj_href); 11 | } else { 12 | $scope.jnj_href = 'data:application/joinnet;base64,' + $rootScope.jnj_base64; 13 | } 14 | $scope.switch_to_download = function() { 15 | appSetting.switch_to_download(); 16 | } 17 | $scope.launch_native = function() { 18 | if(window.navigator.msSaveOrOpenBlob && $scope.blob) { 19 | window.navigator.msSaveOrOpenBlob($scope.blob, $scope.jnj_name); 20 | } 21 | } 22 | $scope.connect = function() { 23 | if(!$scope.jnj_source) return; 24 | 25 | hmtgHelper.inside_angular++; 26 | if(hmtg.jmkernel.jm_callback_LaunchJoinNet) hmtg.jmkernel.jm_callback_LaunchJoinNet(hmtg.util.encodeUtf8($scope.jnj_source)); 27 | hmtgHelper.inside_angular--; 28 | } 29 | } 30 | ]) 31 | ; 32 | -------------------------------------------------------------------------------- /lazy_js/option_msgr.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('MsgrSettingCtrl', ['$scope', 'Msgr', 'appSetting', 'jnagentDlg', '$rootScope', 'hmtgHelper', 3 | function ($scope, Msgr, appSetting, jnagentDlg, $rootScope, hmtgHelper) { 4 | $scope.w = appSetting; 5 | 6 | $scope.$watch('w.show_text', function () { 7 | hmtg.util.localStorage['hmtg_show_text'] = JSON.stringify($scope.w.show_text); 8 | }); 9 | $scope.$watch('w.no_tip', function() { 10 | hmtg.util.localStorage['hmtg_no_tip'] = JSON.stringify($scope.w.no_tip); 11 | }); 12 | 13 | $scope.$watch('w.auto_https', function() { 14 | hmtg.util.localStorage['hmtg_auto_https'] = JSON.stringify($scope.w.auto_https); 15 | }); 16 | 17 | $scope.$watch('w.alert_online', function () { 18 | hmtg.util.localStorage['hmtg_alert_online'] = JSON.stringify($scope.w.alert_online); 19 | }); 20 | $scope.$watch('w.alert_newmessage', function () { 21 | hmtg.util.localStorage['hmtg_alert_newmessage'] = JSON.stringify($scope.w.alert_newmessage); 22 | }); 23 | $scope.$watch('w.play_sound', function () { 24 | hmtg.util.localStorage['hmtg_play_sound'] = JSON.stringify($scope.w.play_sound); 25 | }); 26 | $scope.$watch('w.vibrate', function() { 27 | hmtg.util.localStorage['hmtg_vibrate'] = JSON.stringify($scope.w.vibrate); 28 | }); 29 | $scope.$watch('w.show_other_user', function() { 30 | hmtg.util.localStorage['hmtg_show_other_user'] = JSON.stringify($scope.w.show_other_user); 31 | hmtgHelper.inside_angular++; 32 | jnagentDlg.update_show_user(); 33 | hmtgHelper.inside_angular--; 34 | }); 35 | $scope.$watch('w.show_offline_user', function () { 36 | hmtg.util.localStorage['hmtg_show_offline_user'] = JSON.stringify($scope.w.show_offline_user); 37 | hmtgHelper.inside_angular++; 38 | jnagentDlg.update_show_user(); 39 | hmtgHelper.inside_angular--; 40 | }); 41 | $scope.$watch('w.max_win', function () { 42 | hmtg.util.localStorage['hmtg_max_win'] = JSON.stringify($scope.w.max_win); 43 | hmtgHelper.inside_angular++; 44 | $rootScope.$broadcast(hmtgHelper.WM_MAX_WIN_CHANGED); 45 | hmtgHelper.inside_angular--; 46 | }); 47 | 48 | } 49 | ]) 50 | ; -------------------------------------------------------------------------------- /lazy_js/option_webrtc.js: -------------------------------------------------------------------------------- 1 | angular.module('hmtgs') 2 | .controller('WebRTCSettingCtrl', ['$scope', 'appSetting', 'hmtgHelper', '$rootScope', '$translate', 'mediasoupWebRTC', 3 | function($scope, appSetting, hmtgHelper, $rootScope, $translate, mediasoupWebRTC) { 4 | $scope.w = {}; 5 | $scope.as = appSetting; 6 | $scope.ms = mediasoupWebRTC; 7 | 8 | $scope.w.edit_server = $scope.w.edit_username = $scope.w.edit_password = ''; 9 | 10 | $scope.add_turn_server = function() { 11 | if($scope.ms.turn_server_array.length >= 10) { 12 | hmtgSound.ShowErrorPrompt(function() { return $translate.instant('ID_TOO_MANY_TURN_SERVER') }, 20); 13 | return; 14 | } 15 | 16 | $scope.w.edit_server = $scope.w.edit_username = $scope.w.edit_password = ''; 17 | 18 | var item = { server: '', username: '', password: '', edit: 1 }; 19 | $scope.w.editing = true; 20 | $scope.ms.turn_server_array.unshift(item); 21 | } 22 | 23 | $scope.edit = function(item) { 24 | item.edit = 2; 25 | $scope.w.editing = true; 26 | $scope.w.edit_server = item.server; 27 | $scope.w.edit_username = item.username; 28 | $scope.w.edit_password = item.password; 29 | } 30 | 31 | $scope.ok = function(item) { 32 | if(!$scope.w.edit_server) return; 33 | item.server = $scope.w.edit_server; 34 | item.username = $scope.w.edit_username; 35 | item.password = $scope.w.edit_password; 36 | item.edit = 0; 37 | $scope.w.editing = false; 38 | 39 | hmtg.util.localStorage['hmtg_turn_server_array'] = JSON.stringify($scope.ms.turn_server_array); 40 | } 41 | 42 | $scope.cancel = function(item) { 43 | if(item.edit == 1) { 44 | $scope.ms.turn_server_array.shift(); 45 | } else { 46 | item.edit = 0; 47 | } 48 | $scope.w.editing = false; 49 | } 50 | 51 | $scope.remove = function(item) { 52 | var idx = $scope.ms.turn_server_array.indexOf(item); 53 | if(idx != -1) { 54 | hmtgHelper.OKCancelMessageBox($translate.instant('ID_DELETE_TURN_SERVER_PROMPT'), 0, ok); 55 | } 56 | function ok() { 57 | $scope.w.edit_server = item.server; 58 | $scope.w.edit_username = item.username; 59 | $scope.w.edit_password = item.password; 60 | $scope.ms.turn_server_array.splice(idx, 1); 61 | hmtg.util.localStorage['hmtg_turn_server_array'] = JSON.stringify($scope.ms.turn_server_array); 62 | } 63 | } 64 | 65 | $scope.move_up = function(item) { 66 | var idx = $scope.ms.turn_server_array.indexOf(item); 67 | if(idx == -1) return; 68 | if(idx == 0) return; 69 | 70 | $scope.ms.turn_server_array.splice(idx, 1) 71 | $scope.ms.turn_server_array.splice(idx - 1, 0, item); 72 | hmtg.util.localStorage['hmtg_url_array'] = JSON.stringify($scope.ms.turn_server_array); 73 | } 74 | 75 | $scope.move_down = function(item) { 76 | var idx = $scope.ms.turn_server_array.indexOf(item); 77 | if(idx == -1) return; 78 | if(idx == $scope.ms.turn_server_array.length - 1) return; 79 | 80 | $scope.ms.turn_server_array.splice(idx, 1) 81 | $scope.ms.turn_server_array.splice(idx + 1, 0, item); 82 | hmtg.util.localStorage['hmtg_url_array'] = JSON.stringify($scope.ms.turn_server_array); 83 | } 84 | 85 | } 86 | ]) 87 | ; -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Web JoinNet", 3 | "name": "Web JoinNet", 4 | "icons": [ 5 | { 6 | "src": "img/jnagent_48x48.png", 7 | "sizes": "48x48", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "img/jnagent_72x72.png", 12 | "sizes": "72x72", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "img/jnagent_512x512.png", 17 | "sizes": "512x512", 18 | "type": "image/png" 19 | } 20 | ], 21 | "display": "fullscreen" 22 | } 23 | -------------------------------------------------------------------------------- /media/alert.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/alert.mp3 -------------------------------------------------------------------------------- /media/alert.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/alert.ogg -------------------------------------------------------------------------------- /media/alert.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/alert.wav -------------------------------------------------------------------------------- /media/online.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/online.mp3 -------------------------------------------------------------------------------- /media/online.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/online.ogg -------------------------------------------------------------------------------- /media/online.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/online.wav -------------------------------------------------------------------------------- /media/ringin.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/ringin.mp3 -------------------------------------------------------------------------------- /media/ringin.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/ringin.ogg -------------------------------------------------------------------------------- /media/ringin.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/ringin.wav -------------------------------------------------------------------------------- /media/small.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/small.mp4 -------------------------------------------------------------------------------- /media/small.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/small.webm -------------------------------------------------------------------------------- /media/speaker.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/speaker.mp3 -------------------------------------------------------------------------------- /media/speaker.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/speaker.ogg -------------------------------------------------------------------------------- /media/speaker.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/speaker.wav -------------------------------------------------------------------------------- /media/type.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/type.mp3 -------------------------------------------------------------------------------- /media/type.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/type.ogg -------------------------------------------------------------------------------- /media/type.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/media/type.wav -------------------------------------------------------------------------------- /msgr/icon.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('msgr') 8 | 9 | .service('msgrIcon', [ 10 | function () { 11 | this.ICON_INDEX_SERVER = "img/icon_server.png"; 12 | this.ICON_INDEX_SERVER2 = "img/icon_server2.png"; 13 | this.ICON_INDEX_DUMMY = "img/icon_dummy_16x16.png"; 14 | this.ICON_INDEX_USER = "img/icon_user.png"; 15 | this.ICON_INDEX_SERVER_MMC = "img/icon_server_mmc.png"; 16 | this.ICON_INDEX_USER_OFFLINE = "img/icon_user_offline.png"; 17 | this.ICON_INDEX_USER_BUSY = "img/icon_user_busy.png"; 18 | this.ICON_INDEX_USER_AWAY = "img/icon_user_away.png"; 19 | this.ICON_INDEX_USER_IN_MEETING = "img/icon_user_inmeeting.png"; 20 | this.ICON_INDEX_USER_OPEN = "img/icon_user_open.png"; 21 | this.ICON_INDEX_USER_MOBILE = "img/icon_user_mobile.png"; 22 | this.ICON_INDEX_USER_WEB = "img/icon_user_web.png"; 23 | this.ICON_INDEX_USER_ONLINE = "img/icon_user_online.png"; 24 | this.ICON_INDEX_USER_FOLDED = "img/icon_user_folded.png"; 25 | this.ICON_INDEX_USER_UNFOLDED = "img/icon_user_unfolded.png"; 26 | this.ICON_INDEX_USER_VISITOR = "img/icon_user_visitor.png"; 27 | this.ICON_INDEX_USER_MISSED_CALL = "img/icon_missed_call.png"; 28 | this.ICON_INDEX_EVENT_ONGOING = "img/icon_event_ongoing.png"; 29 | this.ICON_INDEX_EVENT_UPCOMING = "img/icon_event_upcoming.png"; 30 | this.ICON_INDEX_SHARE_FILE = "img/icon_file_shared.png"; 31 | this.ICON_INDEX_PUBLISH_FILE = "img/icon_file.png"; 32 | this.ICON_INDEX_SHARE_FILE_READ = "img/icon_file_shared_read.png"; 33 | this.ICON_INDEX_IM = "img/icon_im.png"; 34 | this.ICON_INDEX_PGC_PEER = "img/icon_user_online.png"; 35 | this.ICON_INDEX_PGC_GUEST = "img/icon_server.png"; 36 | this.ICON_INDEX_PGC_GROUP = "img/icon_user_inmeeting.png"; 37 | this.ICON_INDEX_FILE = "img/icon_file.png"; 38 | this.ICON_INDEX_FILE_ENCRYPTED = "img/icon_file_encrypted.png"; 39 | this.ICON_INDEX_FILE_SHARED = "img/icon_file_shared.png"; 40 | this.ICON_INDEX_FILE_ENCRYPTED_SHARED = "img/icon_file_encrypted_shared.png"; 41 | this.ICON_INDEX_FILE_READ = "img/icon_file_read.png"; 42 | this.ICON_INDEX_FILE_READ_ENCRYPTED = "img/icon_file_read_encrypted.png"; 43 | this.ICON_INDEX_FILE_READ_SHARED = "img/icon_file_read_encrypted.png"; 44 | this.ICON_INDEX_FILE_READ_ENCRYPTED_SHARED = "img/icon_file_read_encrypted_sahred.png"; 45 | } 46 | ]) 47 | 48 | ; 49 | -------------------------------------------------------------------------------- /msgr/missedCall.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Web JoinNet 3 | * Copyright © 2019, John Liu 4 | * HomeMeeting Inc. 5 | */ 6 | 7 | angular.module('msgr') 8 | 9 | .service('missedCall', ['$translate', 'appSetting', 'hmtgHelper', '$rootScope', 10 | function($translate, appSetting, hmtgHelper, $rootScope) { 11 | var _missedCall = this; 12 | this.missed_call_array = read_missed_call(); 13 | 14 | function read_missed_call() { 15 | var array = []; 16 | try { 17 | array = typeof hmtg.util.localStorage['hmtg_missed_call_array'] === 'undefined' ? [] : JSON.parse(hmtg.util.localStorage['hmtg_missed_call_array']); 18 | if(!hmtg.util.isArray(array)) return []; 19 | } catch(e) { 20 | return []; 21 | } 22 | return array; 23 | } 24 | 25 | this.checkMissedCall = function() { 26 | var array = _missedCall.missed_call_array; 27 | 28 | if(array.length == 0) return; 29 | 30 | // relay to the controller 31 | this.to_check_missed_call = true; 32 | $rootScope.selectTabMissedCall(); 33 | } 34 | 35 | function write_missed_call() { 36 | var array = _missedCall.missed_call_array; 37 | hmtg.util.localStorage['hmtg_missed_call_array'] = JSON.stringify(array); 38 | } 39 | 40 | this.update_missed_call = function(tid, name) { 41 | var now = Date.now(); 42 | var item = { tid: tid, name: name, tick: now, time_str: (new Date()).toString().replace(/(GMT.*)/, "") }; 43 | var array = _missedCall.missed_call_array = read_missed_call(); 44 | array.unshift(item); 45 | if(array.length > 200) { 46 | array.shift(); 47 | } 48 | write_missed_call(); 49 | $rootScope.$apply(); 50 | } 51 | 52 | this.remove_missed_call = function(missed_call) { 53 | var array = _missedCall.missed_call_array = read_missed_call(); 54 | var i; 55 | for(i = 0; i < array.length; i++) { 56 | if(array[i].missed_call == missed_call) { 57 | array.splice(i, 1); 58 | break; 59 | } 60 | } 61 | write_missed_call(); 62 | $rootScope.$apply(); 63 | } 64 | 65 | this.reset_missed_call = function() { 66 | this.missed_call_array = []; 67 | write_missed_call(); 68 | } 69 | 70 | this.delete_missed_call = function(item) { 71 | var array = _missedCall.missed_call_array = read_missed_call(); 72 | var i; 73 | for(i = 0; i < array.length; i++) { 74 | if(array[i].missed_call == item.missed_call) { 75 | array.splice(i, 1); 76 | write_missed_call(); 77 | break; 78 | } 79 | } 80 | } 81 | } 82 | ]) 83 | 84 | ; 85 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | whiteboard is used for sharing board between joined users 2 | -------------------------------------------------------------------------------- /sw.js: -------------------------------------------------------------------------------- 1 | //self.CACHE_NAME = 'hmtg-webjoinnet-cache-1.0.0.8d'; 2 | 3 | self.addEventListener('install', function(event) { 4 | /* 5 | event.waitUntil( 6 | caches.open(self.CACHE_NAME) 7 | .then(function(cache) { 8 | return cache.addAll([]); 9 | }) 10 | ); 11 | */ 12 | }); 13 | 14 | self.addEventListener('activate', function(event) { 15 | self.clients.matchAll().then(function(clientList) { 16 | if(clientList) { 17 | for(var i = 0; i < clientList.length; i++) { 18 | client = clientList[i]; 19 | client.postMessage({ 20 | cmd: 'client_id', data: clientList[0].id 21 | }); 22 | } 23 | } 24 | }); 25 | 26 | /* 27 | var cacheWhitelist = []; 28 | 29 | event.waitUntil( 30 | caches.keys().then(function(cacheNames) { 31 | return Promise.all( 32 | cacheNames.map(function(cacheName) { 33 | if (cacheWhitelist.indexOf(cacheName) === -1) { 34 | return caches.delete(cacheName); 35 | } 36 | }) 37 | ); 38 | }) 39 | ); 40 | */ 41 | }); 42 | 43 | self.addEventListener('message', function(event) { 44 | if(event.data) { 45 | switch(event.data.cmd) { 46 | case 'client_id': 47 | event.source.postMessage({ cmd: 'client_id', data: event.source.id }); 48 | break; 49 | default: 50 | break; 51 | } 52 | } 53 | }); 54 | 55 | self.addEventListener('notificationclick', function(event) { 56 | event.notification.close(); 57 | 58 | var client_id = ''; 59 | if(event.notification.data && event.notification.data.client_id) { 60 | client_id = event.notification.data.client_id; 61 | } 62 | 63 | var url = ''; 64 | if(event.notification.data && event.notification.data.url) { 65 | url = event.notification.data.url; 66 | } 67 | 68 | // This looks to see if the current is already open and 69 | // focuses if it is 70 | event.waitUntil(clients.matchAll({ 71 | type: "window" 72 | }).then(function(clientList) { 73 | //if (event.action === 'archive') 74 | if(clientList) { 75 | var client = null; 76 | for(var i = 0; i < clientList.length; i++) { 77 | client = clientList[i]; 78 | if(client_id && client.id == client_id) { 79 | //client.postMessage({ cmd: 'notificationclick', data: data }); 80 | return client.focus(); 81 | } 82 | } 83 | } 84 | if(url) { 85 | clients.openWindow(url); 86 | } 87 | })); 88 | }); 89 | 90 | /* 91 | self.addEventListener('fetch', function(event) { 92 | event.respondWith(caches.match(event.request).then(function(response) { 93 | // Cache hit - return response 94 | if(response) { 95 | console.log('hit cache, type: ' + response.type + ', url=' + response.url); 96 | return response; 97 | } 98 | // IMPORTANT: Clone the request. A request is a stream and 99 | // can only be consumed once. Since we are consuming this 100 | // once by cache and once by the browser for fetch, we need 101 | // to clone the response. 102 | var fetchRequest = event.request.clone(); 103 | 104 | return fetch(fetchRequest).then( 105 | function(response) { 106 | // Check if we received a valid response 107 | if(!response || response.status !== 200 || response.type !== 'basic') { 108 | return response; 109 | } 110 | 111 | // IMPORTANT: Clone the response. A response is a stream 112 | // and because we want the browser to consume the response 113 | // as well as the cache consuming the response, we need 114 | // to clone it so we have two streams. 115 | var responseToCache = response.clone(); 116 | 117 | caches.open(self.CACHE_NAME) 118 | .then(function(cache) { 119 | cache.put(event.request, responseToCache); 120 | console.log('added to cache, type: ' + response.type + ', url=' + response.url); 121 | }); 122 | 123 | return response; 124 | }); 125 | })); 126 | }); 127 | */ 128 | -------------------------------------------------------------------------------- /template/ChangeJnrPassword.htm: -------------------------------------------------------------------------------- 1 | 6 | 25 | 29 | -------------------------------------------------------------------------------- /template/DeleteSlide.htm: -------------------------------------------------------------------------------- 1 | 4 | 16 | 20 | -------------------------------------------------------------------------------- /template/DownloadComplete.htm: -------------------------------------------------------------------------------- 1 | 5 | 12 | 16 | -------------------------------------------------------------------------------- /template/EditProfile.htm: -------------------------------------------------------------------------------- 1 | 5 | 45 | 55 | -------------------------------------------------------------------------------- /template/ImportMedia.htm: -------------------------------------------------------------------------------- 1 | 4 | 43 | 51 | -------------------------------------------------------------------------------- /template/MeetingControl.htm: -------------------------------------------------------------------------------- 1 | 4 | 28 | 32 | -------------------------------------------------------------------------------- /template/MoveOffice.htm: -------------------------------------------------------------------------------- 1 |
2 | 5 | 35 |
36 | 39 | -------------------------------------------------------------------------------- /template/PickUser.htm: -------------------------------------------------------------------------------- 1 |
2 | 6 | 75 |
76 | 80 | -------------------------------------------------------------------------------- /template/PlaybackJumpTo.htm: -------------------------------------------------------------------------------- 1 | 4 | 39 | 43 | -------------------------------------------------------------------------------- /template/PollRequest.htm: -------------------------------------------------------------------------------- 1 | 4 | 15 | 19 | -------------------------------------------------------------------------------- /template/PollResult.htm: -------------------------------------------------------------------------------- 1 |
2 | 5 | 28 |
29 | 45 | -------------------------------------------------------------------------------- /template/PromptPassword.htm: -------------------------------------------------------------------------------- 1 | 4 | 12 | 16 | -------------------------------------------------------------------------------- /template/Rename.htm: -------------------------------------------------------------------------------- 1 | 5 | 12 | 16 | -------------------------------------------------------------------------------- /template/ShortMessage.htm: -------------------------------------------------------------------------------- 1 | 4 | 12 | 16 | -------------------------------------------------------------------------------- /template/Snapshot.htm: -------------------------------------------------------------------------------- 1 | 4 | 57 | 60 | -------------------------------------------------------------------------------- /template/Style.htm: -------------------------------------------------------------------------------- 1 | 4 | 45 | 49 | -------------------------------------------------------------------------------- /template/ViewRecord.htm: -------------------------------------------------------------------------------- 1 |
2 | 6 | 35 |
36 | 45 | -------------------------------------------------------------------------------- /template/WebOfficeVisitor.htm: -------------------------------------------------------------------------------- 1 | 4 | 22 | 26 | -------------------------------------------------------------------------------- /template/imTitle.htm: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 39 | 40 | {{im.title}} 41 | 42 | -------------------------------------------------------------------------------- /template/jeditor.htm: -------------------------------------------------------------------------------- 1 | 5 | 51 | 55 | -------------------------------------------------------------------------------- /template/msgrSignin.htm: -------------------------------------------------------------------------------- 1 | 4 | 42 | 46 | -------------------------------------------------------------------------------- /whiteboard_new.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheekey0x/webjoinnet-angularjs/ea22f6c547e088d7e5ff5a97f2cd05eef30de601/whiteboard_new.js -------------------------------------------------------------------------------- /worker/g711_decode.js: -------------------------------------------------------------------------------- 1 | var SIGN_BIT = (0x80); /* Sign bit for a A-law byte. */ 2 | var QUANT_MASK = (0xf); /* Quantization field mask. */ 3 | var BIAS = (0x84); /* Bias for linear code. */ 4 | var SEG_SHIFT = (4); /* Left shift for segment number. */ 5 | var SEG_MASK = (0x70); /* Segment field mask. */ 6 | 7 | var config = {}; 8 | config.MEDIA_AUDIO_G711_50MS = 6; 9 | config.MEDIA_AUDIO_G711_20MS = 7; 10 | config.MEDIA_AUDIO_G711_11K_89K_40MS = 14; 11 | 12 | var good_worker = false; 13 | var sampleRate = 8000; 14 | 15 | this.onmessage = function (e) { 16 | var data = e.data; 17 | switch(data.command) { 18 | case 'init': 19 | sampleRate = data.sampleRate; 20 | good_worker = data.good_worker; 21 | break; 22 | case 'exit': 23 | self.close(); 24 | break; 25 | case 'data_in': 26 | decode(data.media_type, data.data); 27 | break; 28 | default: 29 | break; 30 | } 31 | }; 32 | 33 | function decode(media_type, data) { 34 | var sampleRate0; 35 | if(media_type == config.MEDIA_AUDIO_G711_11K_89K_40MS) { 36 | sampleRate0 = 11025; 37 | } else { 38 | sampleRate0 = 8000; 39 | } 40 | var target_length0 = data.length * sampleRate / sampleRate0; 41 | var target_length = target_length0 >>> 0; 42 | target_length0 -= target_length; 43 | if(Math.random() < target_length0) target_length++; 44 | 45 | var target = new Float32Array(target_length); 46 | target[0] = ulaw2linear(data[0]) / 0x8000; 47 | var i; 48 | if(data.length == target_length) { 49 | for(i = 1; i < target_length; i++) { 50 | target[i] = ulaw2linear(data[i]) / 0x8000; 51 | } 52 | } else { 53 | for(i = 1; i < target_length; i++) { 54 | target[i] = ulaw2linear(data[(i * data.length / target_length) >>> 0]) / 0x8000; 55 | } 56 | } 57 | 58 | if(good_worker) { 59 | self.postMessage({ command: 'data_out', data: target }, [target.buffer]); 60 | } else { 61 | self.postMessage({ command: 'data_out', data: target }); 62 | } 63 | } 64 | 65 | function ulaw2linear(u_val) { 66 | var t; 67 | 68 | /* Complement to obtain normal u-law value. */ 69 | u_val = ~u_val; 70 | 71 | /* 72 | * Extract and bias the quantization bits. Then 73 | * shift up by the segment number and subtract out the bias. 74 | */ 75 | t = ((u_val & QUANT_MASK) << 3) + BIAS; 76 | t <<= (u_val & SEG_MASK) >> SEG_SHIFT; 77 | 78 | return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /worker/gzip_helper.js: -------------------------------------------------------------------------------- 1 | importScripts("gzip.min.js"); 2 | importScripts("gunzip.min.js"); 3 | importScripts("zlib.min.js"); 4 | //https://github.com/imaya/zlib.js 5 | 6 | var good_worker = false; 7 | 8 | this.onmessage = function (e) { 9 | var data = e.data; 10 | switch(data.command) { 11 | case 'init': 12 | good_worker = data.good_worker; 13 | break; 14 | case 'exit': 15 | self.close(); 16 | break; 17 | case 'zip': 18 | try { 19 | // compression type 20 | // 0: none 21 | // 2: dynamic compression 22 | var option = { deflateOptions: { compressionType: data.compression_type} }; 23 | var gzip = new Zlib.Gzip(data.data, option); 24 | var output = gzip.compress(); 25 | if(!output || !output.length) { 26 | self.postMessage({ command: 'error' }); 27 | return; 28 | } 29 | if(good_worker) { 30 | self.postMessage({ command: 'data_out', data: output }, [output.buffer]); 31 | } else { 32 | self.postMessage({ command: 'data_out', data: output }); 33 | } 34 | } catch(e) { 35 | self.postMessage({ command: 'error' }); 36 | return; 37 | } 38 | 39 | break; 40 | case 'unzip': 41 | try { 42 | var gunzip = new Zlib.Gunzip(data.data); 43 | var output = gunzip.decompress(); 44 | if(!output || !output.length) { 45 | self.postMessage({ command: 'error' }); 46 | return; 47 | } 48 | if(good_worker) { 49 | self.postMessage({ command: 'data_out', data: output }, [output.buffer]); 50 | } else { 51 | self.postMessage({ command: 'data_out', data: output }); 52 | } 53 | } catch(e) { 54 | self.postMessage({ command: 'error' }); 55 | return; 56 | } 57 | break; 58 | case 'zlib_compress': 59 | try { 60 | var deflate = new Zlib.Deflate(data.data); 61 | var output = deflate.compress(); 62 | if(!output || !output.length) { 63 | self.postMessage({ command: 'error' }); 64 | return; 65 | } 66 | if(good_worker) { 67 | self.postMessage({ command: 'data_out', data: output }, [output.buffer]); 68 | } else { 69 | self.postMessage({ command: 'data_out', data: output }); 70 | } 71 | } catch(e) { 72 | self.postMessage({ command: 'error' }); 73 | return; 74 | } 75 | 76 | break; 77 | case 'zlib_decompress': 78 | try { 79 | var inflate = new Zlib.Inflate(data.data); 80 | var output = inflate.decompress(); 81 | if(!output || !output.length) { 82 | self.postMessage({ command: 'error' }); 83 | return; 84 | } 85 | if(good_worker) { 86 | self.postMessage({ command: 'data_out', data: output }, [output.buffer]); 87 | } else { 88 | self.postMessage({ command: 'data_out', data: output }); 89 | } 90 | } catch(e) { 91 | self.postMessage({ command: 'error' }); 92 | return; 93 | } 94 | break; 95 | default: 96 | break; 97 | } 98 | }; 99 | 100 | -------------------------------------------------------------------------------- /worker/h264_decode.js: -------------------------------------------------------------------------------- 1 | importScripts('avc-codec.js'); 2 | importScripts('avc.js'); 3 | //https://github.com/mbebenita/broadway 4 | //http://bkw.github.io/Broadway/storyDemo.html 5 | 6 | var good_worker = false; 7 | var avc; 8 | var decoded_ok = false; 9 | 10 | var clip = new Uint8Array(1024); 11 | var tab_rv = new Uint16Array(256); 12 | var tab_gu = new Uint16Array(256); 13 | var tab_gv = new Uint16Array(256); 14 | var tab_bu = new Uint16Array(256); 15 | 16 | this.onmessage = function (e) { 17 | var data = e.data; 18 | switch(data.command) { 19 | case 'init': 20 | good_worker = data.good_worker; 21 | init(); 22 | break; 23 | case 'exit': 24 | self.close(); 25 | break; 26 | case 'data_in': 27 | try { 28 | decoded_ok = false; 29 | avc.decode(data.data); 30 | } catch(e) { 31 | //if(!decoded_ok) self.postMessage({ command: 'data_error' }); 32 | } 33 | if(!decoded_ok) { 34 | self.postMessage({ command: 'data_error' }); 35 | } 36 | break; 37 | default: 38 | break; 39 | } 40 | }; 41 | 42 | function init() { 43 | var defaultConfig = { 44 | filter: "original", 45 | filterHorLuma: "optimized", 46 | filterVerLumaEdge: "optimized", 47 | getBoundaryStrengthsA: "optimized" 48 | }; 49 | avc = new Avc(); 50 | avc.configure(defaultConfig); 51 | avc.onPictureDecoded = onPictureDecoded; 52 | init_table(); 53 | } 54 | 55 | function onPictureDecoded(buffer, width, height) { 56 | decoded_ok = true; 57 | 58 | if(!buffer) { 59 | self.postMessage({ command: 'data_error' }); 60 | return; 61 | } 62 | 63 | var rgba = new Uint8Array(width * height * 4); 64 | 65 | var lumaSize = width * height; 66 | var chromaSize = lumaSize >> 2; 67 | var y = buffer.subarray(0, lumaSize); 68 | var u = buffer.subarray(lumaSize, lumaSize + chromaSize); 69 | var v = buffer.subarray(lumaSize + chromaSize, lumaSize + 2 * chromaSize); 70 | 71 | var i, j, k, ky, k4; 72 | k = 0; 73 | ky = 0; 74 | var rgb; 75 | for(i = 0; i < (height >> 1); i++) { 76 | for(j = 0; j < (width >> 1); j++) { 77 | k4 = ky << 2; 78 | rgb = yuv2rgb(rgba, k4, y[ky], u[k], v[k]); 79 | rgba[k4 + 3] = 255; 80 | 81 | k4 = (ky + width) << 2; 82 | rgb = yuv2rgb(rgba, k4, y[ky + width], u[k], v[k]); 83 | rgba[k4 + 3] = 255; 84 | 85 | ky++; 86 | 87 | k4 = ky << 2; 88 | rgb = yuv2rgb(rgba, k4, y[ky], u[k], v[k]); 89 | rgba[k4 + 3] = 255; 90 | 91 | k4 = (ky + width) << 2; 92 | rgb = yuv2rgb(rgba, k4, y[ky + width], u[k], v[k]); 93 | rgba[k4 + 3] = 255; 94 | 95 | ky++; 96 | k++; 97 | } 98 | ky += width; 99 | } 100 | 101 | if(good_worker) { 102 | self.postMessage({ command: 'data_out', data: rgba, width: width, height: height }, [rgba.buffer]); 103 | } else { 104 | self.postMessage({ command: 'data_out', data: rgba, width: width, height: height }); 105 | } 106 | } 107 | 108 | function yuv2rgb0(rgba, idx, y, u, v) { 109 | var r, g, b; 110 | 111 | r = y + 1.4075 * (v - 128); 112 | g = y - 0.3455 * (u - 128) - (0.7169 * (v - 128)); 113 | b = y + 1.7790 * (u - 128); 114 | 115 | r = Math.floor(r); 116 | g = Math.floor(g); 117 | b = Math.floor(b); 118 | 119 | if(r < 0) r = 0; 120 | else 121 | if(r > 255) r = 255; 122 | 123 | if(g < 0) g = 0; 124 | else 125 | if(g > 255) g = 255; 126 | 127 | if(b < 0) b = 0; 128 | else 129 | if(b > 255) b = 255; 130 | 131 | rgba[idx] = r; 132 | rgba[idx + 1] = g; 133 | rgba[idx + 2] = b; 134 | } 135 | 136 | function yuv2rgb(rgba, idx, y, u, v) { 137 | rgba[idx] = clip[y + tab_rv[v]]; 138 | rgba[idx + 1] = clip[y + tab_gu[u] + tab_gv[v]]; 139 | rgba[idx + 2] = clip[y + tab_bu[u]]; 140 | } 141 | 142 | function init_table() { 143 | //r = y + 1.4075 * (v - 128); 144 | //g = y - 0.3455 * (u - 128) - (0.7169 * (v - 128)); 145 | //b = y + 1.7790 * (u - 128); 146 | var i; 147 | for(i = 0; i < 256; i++) { 148 | tab_rv[i] = Math.floor(256 + 1.4075 * (i - 128)); 149 | tab_gu[i] = Math.floor(128 - 0.3455 * (i - 128)); 150 | tab_gv[i] = Math.floor(128 - 0.7169 * (i - 128)); 151 | tab_bu[i] = Math.floor(256 + 1.7790 * (i - 128)); 152 | } 153 | 154 | for(i = 512; i < 1024; i++) { 155 | clip[i] = 255; 156 | } 157 | 158 | for(i = 256; i < 512; i++) { 159 | clip[i] = i - 256; 160 | } 161 | } 162 | 163 | -------------------------------------------------------------------------------- /worker/test_worker.js: -------------------------------------------------------------------------------- 1 | var data; 2 | var rate; 3 | var good_worker = false; 4 | 5 | try { 6 | var uInt8Array = new Uint8Array(1); 7 | self.postMessage({ command: '', data: uInt8Array }, [uInt8Array.buffer]); 8 | if(uInt8Array.buffer.byteLength != 0) good_worker = false; 9 | else good_worker = true; 10 | } catch(e) { 11 | good_worker = false; 12 | } 13 | 14 | 15 | this.onmessage = function (e) { 16 | switch(e.data.command) { 17 | case 'data_in': 18 | data = e.data.data; 19 | rate = e.data.sampleRate; 20 | break; 21 | case 'request_data': 22 | request_data(); 23 | break; 24 | case 'trigger_error': 25 | no_such_function(); // this is to trigger an error for testing 26 | break; 27 | default: 28 | setTimeout(function () { self.close(); }, 100); 29 | break; 30 | } 31 | }; 32 | 33 | 34 | function request_data() { 35 | if(good_worker) 36 | self.postMessage({command: 'data_out', data: data, rate: rate}, [data.buffer]); 37 | else 38 | self.postMessage({ command: 'data_out', data: data, rate: rate }); 39 | } 40 | -------------------------------------------------------------------------------- /worker/worker_interval.js: -------------------------------------------------------------------------------- 1 | var id = null; 2 | this.onmessage = function(e) { 3 | switch(e.data.command) { 4 | case 'set': 5 | if(id) { 6 | clearInterval(id); 7 | } 8 | id = setInterval(function() { 9 | id = null; 10 | postMessage('dummy'); 11 | }, (e.data.delay || 0)); 12 | break; 13 | case 'clear': 14 | if(id) { 15 | clearInterval(id); 16 | id = null; 17 | } 18 | break; 19 | case 'exit': 20 | self.close(); 21 | break; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /worker/worker_interval_40.js: -------------------------------------------------------------------------------- 1 | onmessage = function (e) { setInterval(function () { postMessage('dummy'); }, 40) } 2 | -------------------------------------------------------------------------------- /worker/worker_timeout.js: -------------------------------------------------------------------------------- 1 | var id = null; 2 | this.onmessage = function(e) { 3 | switch(e.data.command) { 4 | case 'set': 5 | if(id) { 6 | clearTimeout(id); 7 | } 8 | id = setTimeout(function() { 9 | id = null; 10 | postMessage('dummy'); 11 | }, (e.data.delay || 0)); 12 | break; 13 | case 'clear': 14 | if(id) { 15 | clearTimeout(id); 16 | id = null; 17 | } 18 | break; 19 | case 'exit': 20 | self.close(); 21 | break; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /worker/worklet-record.js: -------------------------------------------------------------------------------- 1 | class RecordProcessor extends AudioWorkletProcessor { 2 | constructor() { 3 | // The super constructor call is required. 4 | super(); 5 | 6 | this.good_worker = false; 7 | this.is_stopped = false; 8 | this.quit_flag = false; 9 | 10 | this.port.onmessage = this.handleMessage.bind(this); 11 | } 12 | 13 | handleMessage(e) { 14 | var data = e.data; 15 | switch(data.command) { 16 | case 'init': 17 | this.quit_flag = false; 18 | this.is_stopped = false; 19 | 20 | this.good_worker = data.good_worker; 21 | 22 | //console.log(`recordWorklet, init, this.good_worker=${this.good_worker}`); 23 | break; 24 | default: 25 | break; 26 | } 27 | } 28 | 29 | process(inputs, outputs) { 30 | if(this.quit_flag) return false; 31 | if(this.is_stopped) return true; 32 | 33 | var input = inputs[0]; 34 | var target = new Float32Array(input[0].length); 35 | target.set(input[0]); 36 | 37 | if(this.good_worker) { 38 | this.port.postMessage({ command: 'data_out', data: target }, [target.buffer]); 39 | } else { 40 | this.port.postMessage({ command: 'data_out', data: target }); 41 | } 42 | 43 | return true; 44 | } 45 | } 46 | 47 | registerProcessor('worklet-record', RecordProcessor); 48 | --------------------------------------------------------------------------------