{{target.name}}
{{chapter.name}}
{{unit.name}}
{{unit.name}}
{{target.release | date:'yyyy/MM/dd'}}
{{item.full_name}}
({{target.reader_size}})
{{previewTarget.name}}
0
{{$index+1}}.
(
)
-->' + '' + '
' }; }]) .controller('CourseController', ['$scope', '$http', '$location', '$timeout', '$compile', '$translate', '$filter', function($scope, $http, $location, $timeout, $compile, $translate, $filter) { var self = this; $scope.service_url = [location.origin, '/private'].join(''); $scope.global = { message: '' }; $scope.contentConversion = function(content) { const originalContent = content; const imgRegex = /
]*>/g; const targetContent = originalContent.replace(imgRegex, function(match, capturedGroup) { return '
'; }); return targetContent; } $scope.openTab = function(url, target) { window.open(url, target); } $scope.changeLanguage = function(lang) { lang = lang.toLowerCase(); if (lang === 'zh-tw') lang = {title: '繁體中文',type: 'zh-tw'}; else if (lang === 'zh-cn') lang = {title: '简体中文',type: 'zh-cn'}; else if (lang === 'es-ar') lang = {title: 'Español (Argentina)',type: 'es-ar'}; else if (lang === 'es-pe') lang = {title: 'Español (Perú)',type: 'es-pe'}; else if (lang === 'de-de') lang = {title: 'Deutsch',type: 'de-de'}; else lang = {title: 'English',type: 'en-us'}; $scope.language = lang; $translate.use(lang.type); if ($scope.target.account) { ga('send', '/personal/profile', 'service', 'put'); $http.put([$scope.service_url, '/personal/profile'].join(''), {language: JSON.stringify(lang)}) .success(function(response, status) { window.scrollTo(0, 0); }); } window.document.title = '均一教育平台 - 數字的寫法與念法 - ' +$filter('translate')('N002'); } $scope.open1know = function() { window.location.href = location.origin; } $scope.signinWithIschool = function() { var width = 800; var height = 700; var top = (screen.height/2)-(height/2); var left = (screen.width/2)-(width/2); var state = encodeURIComponent(['subscribe_knowledge:', $scope.target.uqid].join('')); var target = ['https://auth.ischool.com.tw/oauth/authorize.php?client_id=a266592ce660b43f980d49b4079d53ed&response_type=code&state=', state, '&redirect_uri=', window.location.origin, '/oauth/ischool&lang=', $scope.lang, '&scope=User.Mail,User.BasicInfo,User.Application'].join(''); window.open(target, '1409620722041', ['width=',width,',height=',height,',menubar=0,titlebar=0,status=0,top=',top,',left=',left].join('')).focus(); } /* Sign In with QSchool */ $scope.signinWithQschool = function(type) { var width = 800; var height = 700; var top = (screen.height/2)-(height/2); var left = (screen.width/2)-(width/2); var state = encodeURIComponent($location.url()); var target = ['https://qschool.benq.com.cn/oauth/authorize.php?client_id=a266592ce660b43f980d49b4079d53ed&response_type=code&state=', state, '&redirect_uri=', $scope.BASE_URL, '/oauth/qschool&lang=', $scope.language.type, '&scope=User.Mail,User.BasicInfo,User.Application', type].join(''); window.open(target, '1409620722041', ['width=',width,',height=',height,',menubar=0,titlebar=0,status=0,top=',top,',left=',left].join('')).focus(); } $scope.learn = function() { window.open(["/#!/learn/course/", $scope.target.uqid].join(''), 'myLearnWindow'); } $scope.subscribe = function(type) { ga('send', '/course/:uqid/subscribe', 'service', 'post'); $http.post([$scope.service_url, '/course/', $scope.target.uqid, '/subscribe'].join('')) .success(function(response, status) { if (!response.error) { $scope.target.subscribed = true; if (type == 'course') $('#subscribSuccessModal').modal('show'); } }); } $scope.toSubscribed = function() { window.location.href = [location.origin, "/#!/course/subscribed/", $scope.target.uqid].join(''); } $scope.unsubscribe = function() { ga('send', '/course/:uqid/unsubscribe', 'service', 'delete'); $http.delete([$scope.service_url, '/course/', $scope.target.uqid, '/unsubscribe'].join('')) .success(function(response, status) { $('#unSubscribModal').modal('hide'); $('#subscribSuccessModal').modal('hide'); if (!response.error) { $scope.target.subscribed = false; } }); } $scope.message = { newMessage: { post: function() { var data = { content: $scope.message.newMessage.content }; ga('send', '/course/:uqid/message', 'service', 'post'); $http.post([$scope.service_url, '/course/', $scope.target.uqid, '/message'].join(''), data) .success(function(response, status) { if (!response.error) { $scope.message.load('recent', 0); delete $scope.message.newMessage.content; } }); } }, load: function(type, startIndex, target) { var service = ''; if (type === 'recent') { ga('send', '/course/:uqid/message', 'service', 'get'); service = [$scope.service_url, '/course/', $scope.target.uqid, '/message?start-index=', startIndex, ($scope.message.queryText ? ['&keyword=',$scope.message.queryText].join('') : '')].join('') $scope.message.startIndex = startIndex; } else if (type === 'reply') { ga('send', '/course/message/:uqid/reply', 'service', 'get'); service = [$scope.service_url, '/course/message/', target.uqid, '/reply'].join(''); } $http.get(service) .success(function(response, status) { angular.forEach(response, function(item) { item.msgType = type; item.time_desc = $filter('date')(item.time, 'yyyy-MM-dd @HH:mm:ss'); if (item.msgType === 'reply') item.parent = target; if (item.content) item.content_desc = item.content.replace(/\r\n|\r|\n/g, '
').replace(/</g, '<').replace(/>/g, '>'); item.toggle = function() { if (this.onEdit) return; this.showReply = !this.showReply; if (!this.replyMessages) $scope.message.load('reply', null, this); } item.reply = function() { if (!this.replyMessage || this.replyMessage === '') return; var data = { messageUqid: this.uqid, content: this.replyMessage }; var _this = this; ga('send', '/course/:uqid/message', 'service', 'post'); $http.post([$scope.service_url, '/course/', $scope.target.uqid, '/message'].join(''), data) .success(function(response, status) { if (!response.error) { $scope.message.load('reply', null, _this); delete _this.replyMessage; } }); } item.like = function() { var _this = this; ga('send', '/course/message/:uqid/like', 'service', 'post'); $http.post([$scope.service_url, '/course/message/', this.uqid, '/like'].join('')) .success(function(response, status) { if (!response.error) { _this.like_size = response.like; } }); } item.edit = function(event) { this.onEdit = !this.onEdit; this.showReply = false; if (this.onEdit) this.edit_content = this.content_desc; if (event) event.stopPropagation(); } item.update = function() { if (!this.edit_content || this.edit_content === '') return; var data = { content: this.edit_content }; var _this = this; ga('send', '/course/message/:uqid', 'service', 'put'); $http.put([$scope.service_url, '/course/message/', this.uqid].join(''), data) .success(function(response, status) { if (!response.error) { if (_this.msgType === 'recent') $scope.message.load('recent', 0); else if (_this.msgType === 'reply') $scope.message.load('reply', null, _this.parent); } }); } item.delete = function() { var _this = this; ga('send', '/course/message/:uqid', 'service', 'delete'); $http.delete([$scope.service_url, '/course/message/', this.uqid].join('')) .success(function(response, status) { if (!response.error) { if (_this.msgType === 'recent') $scope.message.load('recent', 0); else if (_this.msgType === 'reply') $scope.message.load('reply', null, _this.parent); } }); } }); if (type === 'recent') { if (startIndex === 0) $scope.message.recentMessages = response; else $scope.message.recentMessages = $scope.message.recentMessages.concat(response); if (response.length === 20) $scope.message.moreRecent = true; else delete $scope.message.moreRecent; } else if (type === 'reply') { target.replyMessages = response; target.reply_size = response.length; } }); } } $scope.preview = function(unit) { $scope.previewTarget = unit; $timeout(function(){ var image = new Image(); image.src = [location.origin, '/icon.png'].join(''); image.onload = function() { $timeout(function(){ $('#unit_qrcode').html(''); $('#unit_qrcode').qrcode({ image: image, text: [location.origin, '/#!/learn/unit/', unit.uqid].join(''), // text: [location.origin, '/learning?v=', unit.uqid].join(''), size: 240, render: 'image', mode: 4, mSize: 0.3, background: '#fff', ecLevel: 'Q' }); $('#unit_qrcode img').css('width', '120px').css('height', '120px'); }); } if (unit.unit_type === 'video') { var youtubePath = unit.content_url.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?[^#]*v=|embed\/)?([a-z0-9_\-]+)/i); var vimeoPath = unit.content_url.match(/^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/i); var officeMixPath = unit.content_url.match(/\/\/(?:www\.)?mix.office.com\/(?:watch|embed)?\/([a-z0-9_\-]+)/i); if (youtubePath && youtubePath[1]) { $('#video').html(['
'].join('')); } else if (vimeoPath && vimeoPath[5]) { $('#video').html(['
'].join('')); } else if (officeMixPath && officeMixPath[1]) { $('#video').html(['
'].join('')); } else { var mp3 = unit.content_url.match(/([a-z\-_0-9\/\:\.]*\.mp3)/i); var videoId = Date.now(); if (mp3 === null) { $('#video').html( ['
', '
'].join('') ); } else { unit.sub_type = 'audio'; $('#video').html( ['
', '
'].join('') ); } $timeout(function() { var player = videojs(['video-', videoId].join(''), {controls: true, preload: 'auto'}, function() { }); // 加上字幕 if (unit.content && unit.content.text_track) { [].concat(unit.content && unit.content.text_track || []).forEach(function(item) { if (item && item.src) { var data = { kind: item.kind || 'captions', label: item.label || '', srclang: item.srclang || '', src: item.src || '', }; if (item.default) { data.default = 'default'; } player.addRemoteTextTrack(data); } }); } },100); } } else if (unit.unit_type === 'web') { if (unit.content) { if (unit.content.sandbox) unit.sandbox = true; } else { ga('send', '/utility/parseURL', 'service', 'post'); $http.post([$scope.service_url, '/utility/parseURL'].join(''), { url: unit.content_url }) .success(function(response, status) { if (!response.error) { unit.content = { x_frame_options: response.x_frame_options ? true : false }; } }); } } else if (unit.unit_type === 'quiz') $scope.quiz.list(unit); }); $('#previewModal').on('hidden.bs.modal', function(){ $('#video').html(''); delete $scope.previewTarget; }); $('#previewModal').modal('show'); } $scope.toggleView = function(type) { $scope.viewType = type; $location.search({v: type}); } ga('send', '/knowledge/:uqid.json', 'service', 'get'); $http.get([location.origin, '/course/3b622de026d7.json'].join('')) .success(function(response, status) { $scope.target = response; $scope.target.encode_page = encodeURIComponent(response.landing_page); angular.forEach($scope.target.chapters, function(chapter) { angular.forEach(chapter.units, function(item) { if(item.unit_type == 'poll') { // 因為 2024 開始 google drive 不再支援直接讀取圖片,目前方案是透過 iframe 嵌入 google viewer。 // 因為舊資料的圖片是透過 img tag 嵌入,所以要將 img tag 轉成 iframe tag。 // 使用單元編輯功能修改後,就會直接儲存 iframe tag。 const originalContent = item.content.content || ''; item.content.content = $scope.contentConversion(originalContent); } if (!item.logo) { if (item.unit_type === 'video') { var youtubePath = item.content_url.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?[^#]*v=|embed\/)?([a-z0-9_\-]+)/i); var vimeoPath = item.content_url.match(/^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/i); if (youtubePath && youtubePath[1]) { item.logo = ['http://i.ytimg.com/vi/', youtubePath[1], '/default.jpg'].join(''); } else if (vimeoPath && vimeoPath[5]) { $.get(['http://vimeo.com/api/oembed.json?url=', vimeoPath[0]].join(''), function(response) { $scope.$apply(function() { item.logo = response.thumbnail_url; }); }); } } } }); }); $scope.viewType = $location.$$search.v || 'list'; if ($location.$$search.u !== undefined) { angular.forEach($scope.target.chapters, function(chapter) { angular.forEach(chapter.units, function(item) { if (item.uqid === $location.$$search.u) $scope.preview(item); }); }); $location.search({v: $scope.viewType, u: $location.$$search.u}); } else $location.search({v: $scope.viewType}); $scope.toggleView($scope.viewType); $scope.message.load('recent', 0); var image = new Image(); image.src = [location.origin, '/icon.png'].join(''); image.onload = function() { $timeout(function(){ $('#course_qrcode').html(''); $('#course_qrcode').qrcode({ image: image, text: [location.origin, '/#!/learn/unit/', $scope.target.uqid].join(''), // text: [location.origin, '/learning?list=c', $scope.target.uqid].join(''), size: 240, render: 'image', mode: 4, mSize: 0.3, background: '#fff', ecLevel: 'Q' }); $('#course_qrcode img').css('width', '140px').css('height', '140px'); }); } $('.loading').hide(); $('.completed').show(); if (response.account) { $scope.language = response.account.language; $translate.use($scope.language.type); } else { var lang = 'en-us'; if (window.navigator.language !== undefined) lang = window.navigator.language.toLowerCase(); else if (window.navigator.systemLanguage !== undefined) lang = window.navigator.systemLanguage.toLowerCase(); if (lang === 'zh-tw') lang = {title: '繁體中文',type: 'zh-tw'}; else if (lang === 'zh-cn') lang = {title: '简体中文',type: 'zh-cn'}; else if (lang === 'es-ar') lang = {title: 'Español (Argentina)',type: 'es-ar'}; else if (lang === 'es-pe') lang = {title: 'Español (Perú)',type: 'es-pe'}; else if (lang === 'de-de') lang = {title: 'Deutsch',type: 'de-de'}; else lang = {title: 'English',type: 'en-us'}; $scope.language = lang; $translate.use($scope.language.type); } window.document.title = '均一教育平台 - 數字的寫法與念法 - ' +$filter('translate')('N002'); }); }])