diff --git a/AudioPlayer/Plugin.php b/AudioPlayer/Plugin.php index 4235587a..dfa2761e 100644 --- a/AudioPlayer/Plugin.php +++ b/AudioPlayer/Plugin.php @@ -1,18 +1,49 @@ 'E5E5E5', + 'leftbg'=>'CCCCCC', + 'lefticon'=>'333333', + 'voltrack'=>'FFFFFF', + 'volslider'=>'666666', + 'rightbg'=>'B4B4B4', + 'rightbghover'=>'999999', + 'righticon'=>'333333', + 'righticonhover'=>'FFFFFF', + 'text'=>'333333', + 'tracker'=>'DDDDDD', + 'track'=>'FFFFFF', + 'border'=>'CCCCCC', + 'loader'=>'009900', + 'skip'=>'666666', + ); + /** * 激活插件方法,如果激活失败,直接抛出异常 * @@ -22,11 +53,11 @@ class AudioPlayer_Plugin implements Typecho_Plugin_Interface */ public static function activate() { - Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('AudioPlayer_Plugin', 'playerparse'); - Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('AudioPlayer_Plugin', 'playerparse'); - Typecho_Plugin::factory('Widget_Archive')->header = array('AudioPlayer_Plugin','playerjs'); + Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('AudioPlayer_Plugin','playerparse'); + Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('AudioPlayer_Plugin','playerparse'); + Typecho_Plugin::factory('Widget_Abstract_Contents')->excerpt = array('AudioPlayer_Plugin','textparse'); } - + /** * 禁用插件方法,如果禁用失败,直接抛出异常 * @@ -36,7 +67,7 @@ public static function activate() * @throws Typecho_Plugin_Exception */ public static function deactivate(){} - + /** * 获取插件配置面板 * @@ -47,149 +78,173 @@ public static function deactivate(){} public static function config(Typecho_Widget_Helper_Form $form) { $options = Helper::options(); -?> -
- [mp3]文件地址[/mp3]发布即可. 多个mp3地址可用,号隔开.
-

可带参数autostart(自动播放)loop(循环播放)titles(曲名)artists(艺术家名)用|号隔开.
- 例: %s','[mp3]http://1.mp3,http://2.mp3|titles=简单爱,The Monster|artists=周杰伦,Eminem|autostart=yes|loop=no[/mp3]

'); ?> -
+ //格式化默认配色 + $colors = self::$Colors; + foreach ($colors as $key=>$color) { + $colors[$key] = '#'.$color; + } + $colors = Json::encode($colors); - - - - - - - - -
-
- - - - - -
- -
    - -
  • #
  • - -
-
+//输出面板效果 +?> +
+参数间用%s号隔开, 支持%s(自动播放)%s(循环播放)%s(曲名)%s(艺术家名)等. 示例','[mp3]','[/mp3]',',','|','autostart','loop','titles','artists'); ?> +
+
+[mp3]http://dfp.mp3,http://m.mp3|
+titles=东风破,The Monster|
+artists=周杰伦,Eminem|
+autostart=no|
+loop=
yes[/mp3]
+ + + + + + + + + + +
+
+ + + + + +
+ yzmb.me +
    + +
  • #
  • +
+
-input->setAttribute('class','w-10'); - $ap_width->addRule(array(new AudioPlayer_Plugin,'widthformat'),_t('请输入整数或百分数')); - $ap_width->addRule('required',_t('播放器宽度不能为空')); - $form->addInput($ap_width); +
- $ap_fieldselector= new Typecho_Widget_Helper_Form_Element_Select('ap_fieldselector', +_t('背景'), 'leftbg'=>_t('左侧背景'), - 'lefticon'=>_t('左侧图标(喇叭)'), + 'lefticon'=>_t('左侧图标'), 'voltrack'=>_t('音量背景'), 'volslider'=>_t('音量滑块'), 'rightbg'=>_t('右侧背景'), - 'rightbghover'=>_t('右侧背景(悬停时)'), - 'righticon'=>_t('右侧图标(播放/暂停)'), - 'righticonhover'=>_t('右侧图标(悬停时)'), - 'text'=>_t('文本'),'tracker'=>_t('进度条'), + 'rightbghover'=>_t('右侧背景(悬停)'), + 'righticon'=>_t('右侧图标'), + 'righticonhover'=>_t('右侧图标(悬停)'), + 'text'=>_t('文本'), + 'tracker'=>_t('进度条'), 'track'=>_t('进度条(剩余)'), 'border'=>_t('进度条(边框)'), 'loader'=>_t('加载条'), 'skip'=>_t('切歌按钮') ), - 'bg',_t('配色方案'),' + 'bg',_t('播放器配色'),'
Audio Player
- '); $ap_fieldselector->input->setAttribute('id','ap_fieldselector'); - $ap_fieldselector->input->setAttribute('style','height:23px;'); + $ap_fieldselector->input->setAttribute('style','height:23px'); $form->addInput($ap_fieldselector); - $ap_behaviour = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_behaviour', - array('1'=>_t('将文章内地址为mp3的链接替换成播放器')),NULL,_t('替换mp3链接')); - $form->addInput($ap_behaviour); + if (Typecho_Request::getInstance()->is('action=resetcolor') && isset($options->plugins['activated']['AudioPlayer'])) { + Helper::configPlugin('AudioPlayer',array('ap_colors'=>$colors)); + Typecho_Response::getInstance()->goBack(); + } + //重置动作按钮 + $resetcolor = new Typecho_Widget_Helper_Form_Element_Submit(); + $resetcolor->value(_t('重置')); + $resetcolor->setAttribute('style','position:relative'); + $resetcolor->input->setAttribute('id','ap_resetcolor'); + $resetcolor->input->setAttribute('class','btn btn-xs'); + $resetcolor->input->setAttribute('formaction',Helper::security()->getAdminUrl('options-plugin.php?config=AudioPlayer&action=resetcolor')); + $form->addItem($resetcolor); - $ap_encode = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_encode', - array('1'=>_t('对非法下载或盗链行为起到一定防范作用')),NULL,_t('加密mp3地址')); - $form->addInput($ap_encode); + $ap_width = new Typecho_Widget_Helper_Form_Element_Text('ap_width', + NULL,'290',_t('播放器宽度'),_t('输入像素值(如200不用带px)或百分数(如80%)')); + $ap_width->input->setAttribute('style','width:50px'); + $ap_width->addRule(array(new AudioPlayer_Plugin,'widthformat'),_t('请填写整数或百分数')); + $ap_width->addRule('required',_t('播放器宽度不能为空')); + $form->addInput($ap_width); + + $ap_initialvolume = new Typecho_Widget_Helper_Form_Element_Text('ap_initialvolume', + NULL,'60',_t('初始音量大小'),_t('播放器启动时的音量起步值, 最大100, 默认60')); + $ap_initialvolume->input->setAttribute('style','width:50px'); + $ap_initialvolume->addRule('isInteger',_t('请填写整数数字')); + $ap_initialvolume->addRule('required',_t('初始音量不能为空')); + $form->addInput($ap_initialvolume); + + $ap_buffer = new Typecho_Widget_Helper_Form_Element_Text('ap_buffer', + NULL,'5',_t('缓冲等待时间'),_t('单位秒(不用填写), 视播放卡顿情况可适当提高')); + $ap_buffer->input->setAttribute('style','width:50px'); + $ap_buffer->addRule('isInteger',_t('请填写整数数字')); + $ap_buffer->addRule('required',_t('缓冲时间不能为空')); + $form->addInput($ap_buffer); $ap_animation = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_animation', - array('1'=>_t('省去点击动作让播放器直接处于展开状态')),NULL,_t('禁用动画效果')); + array(1=>_t('省去点击操作让播放器直接处于展开状态')),NULL,_t('禁用动画效果')); $form->addInput($ap_animation); + $ap_encode = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_encode', + array(1=>_t('隐藏文件真实url(不支持HTML5缺省播放)')),NULL,_t('加密mp3地址')); + $form->addInput($ap_encode); + + $ap_behaviour = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_behaviour', + array(1=>_t('将文内指向mp3的链接自动替换成播放器')),NULL,_t('代替mp3链接')); + $form->addInput($ap_behaviour); + $ap_remaining = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_remaining', - array('1'=>_t('显示音频的剩余时长而不是已经播放时长')),NULL,_t('显示剩余时长')); + array(1=>_t('显示音频的剩余倒计时而非已播放的时长')),NULL,_t('显示剩余时长')); $form->addInput($ap_remaining); - $ap_checkpolicy = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_checkpolicy', - array('1'=>_t('检查mp3所在服务器是否允许读取ID3标签')),'1',_t('探测跨域许可')); - $form->addInput($ap_checkpolicy); - $ap_noinfo = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_noinfo', - array('1'=>_t('即使有也不显示曲名/艺术家名等标签信息')),NULL,_t('禁用曲目信息')); + array(1=>_t('隐藏曲名/艺术家名等标签信息仅显示空白')),NULL,_t('禁用曲目信息')); $form->addInput($ap_noinfo); - //配色参数隐藏域 - $filtformat = array(new AudioPlayer_Plugin,'colorformat'); - $ap_bgcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_bgcolor',NULL,'#E5E5E5',NULL); - $ap_bgcolor->input->setAttribute('id','ap_bgcolor'); - $form->addInput($ap_bgcolor->addRule($filtformat)); - $ap_leftbgcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_leftbgcolor',NULL,'#CCCCCC',NULL); - $ap_leftbgcolor->input->setAttribute('id','ap_leftbgcolor'); - $form->addInput($ap_leftbgcolor->addRule($filtformat)); - $ap_lefticoncolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_lefticoncolor',NULL,'#333333',NULL); - $ap_lefticoncolor->input->setAttribute('id','ap_lefticoncolor'); - $form->addInput($ap_lefticoncolor->addRule($filtformat)); - $ap_voltrackcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_voltrackcolor',NULL,'#FFFFFF',NULL); - $ap_voltrackcolor->input->setAttribute('id','ap_voltrackcolor'); - $form->addInput($ap_voltrackcolor->addRule($filtformat)); - $ap_volslidercolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_volslidercolor',NULL,'#666666',NULL); - $ap_volslidercolor->input->setAttribute('id','ap_volslidercolor'); - $form->addInput($ap_volslidercolor->addRule($filtformat)); - $ap_rightbgcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_rightbgcolor',NULL,'#B4B4B4',NULL); - $ap_rightbgcolor->input->setAttribute('id','ap_rightbgcolor'); - $form->addInput($ap_rightbgcolor->addRule($filtformat)); - $ap_rightbghovercolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_rightbghovercolor',NULL,'#999999',NULL); - $ap_rightbghovercolor->input->setAttribute('id','ap_rightbghovercolor'); - $form->addInput($ap_rightbghovercolor->addRule($filtformat)); - $ap_righticoncolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_righticoncolor',NULL,'#333333',NULL); - $ap_righticoncolor->input->setAttribute('id','ap_righticoncolor'); - $form->addInput($ap_righticoncolor->addRule($filtformat)); - $ap_textcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_textcolor',NULL,'#333333',NULL); - $ap_textcolor->input->setAttribute('id','ap_textcolor'); - $form->addInput($ap_textcolor->addRule($filtformat)); - $ap_trackercolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_trackercolor',NULL,'#DDDDDD',NULL); - $ap_trackercolor->input->setAttribute('id','ap_trackercolor'); - $form->addInput($ap_trackercolor->addRule($filtformat)); - $ap_righticonhovercolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_righticonhovercolor',NULL,'#FFFFFF',NULL); - $ap_righticonhovercolor->input->setAttribute('id','ap_righticonhovercolor'); - $form->addInput($ap_righticonhovercolor->addRule($filtformat)); - $ap_trackcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_trackcolor',NULL,'#FFFFFF',NULL); - $ap_trackcolor->input->setAttribute('id','ap_trackcolor'); - $form->addInput($ap_trackcolor->addRule($filtformat)); - $ap_bordercolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_bordercolor',NULL,'#CCCCCC',NULL); - $ap_bordercolor->input->setAttribute('id','ap_bordercolor'); - $form->addInput($ap_bordercolor->addRule($filtformat)); - $ap_loadercolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_loadercolor',NULL,'#009900',NULL); - $ap_loadercolor->input->setAttribute('id','ap_loadercolor'); - $form->addInput($ap_loadercolor->addRule($filtformat)); - $ap_skipcolor = new Typecho_Widget_Helper_Form_Element_Hidden('ap_skipcolor',NULL,'#666666',NULL); - $ap_skipcolor->input->setAttribute('id','ap_skipcolor'); - $form->addInput($ap_skipcolor->addRule($filtformat)); + $ap_html5 = new Typecho_Widget_Helper_Form_Element_Checkbox('ap_html5', + array(1=>_t('若浏览器不支持flash则显示HTML5播放器')),1,_t('使用缺省播放')); + $form->addInput($ap_html5); + + //配色保存隐藏域 + $ap_colors = new Typecho_Widget_Helper_Form_Element_Hidden('ap_colors',NULL,$colors,NULL); + $ap_colors->input->setAttribute('id','ap_colors'); + $form->addInput($ap_colors); } + /** * 个人用户的配置面板 * @@ -200,195 +255,189 @@ public static function config(Typecho_Widget_Helper_Form $form) public static function personalConfig(Typecho_Widget_Helper_Form $form){} /** - * 标签链接替换 + * 内容标签替换 * * @param string $content * @return string */ public static function playerparse($content,$widget,$lastResult) { - $content = empty($lastResult)?$content:$lastResult; - $settings = Helper::options()->plugin('AudioPlayer'); + $content = empty($lastResult) ? $content : $lastResult; + + if ($widget instanceof Widget_Archive && !$widget->request->feed && false!==stripos($content,'[mp3]')) { + $pattern = '/\[(mp3)](.*?)\[\/\\1]/si'; + $callback = array('AudioPlayer_Plugin','parseCallback'); + + //替换播放器标签 + $content = preg_replace_callback($pattern,$callback,$content); - if ($widget instanceof Widget_Archive) { //替换mp3链接 - if ($settings->ap_behaviour) { - $pattern = "/([^<]+)<\/a>/is"; - $content = preg_replace_callback($pattern,array('AudioPlayer_Plugin',"parseCallback"),$content); + if (Helper::options()->plugin('AudioPlayer')->ap_behaviour) { + $content = preg_replace_callback('/.*?<\/a>/si',$callback,$content); } - $content = preg_replace_callback("/\[(mp3)](([^]]+))\[\/\\1]/si",array('AudioPlayer_Plugin',"parseCallback"),$content); } return $content; } /** - * 参数回调解析 + * 摘要文本替换 * - * @param array $matches + * @param string $text * @return string */ - public static function parseCallback($matches) + public static function textparse($text,$widget,$lastResult) { - $atts = explode("|",$matches[3]); - $data[0] = $atts[0]; + $text = empty($lastResult) ? $text : $lastResult; - for ($i=1;$iplugin('AudioPlayer'); - $archive = Typecho_Widget::widget('Widget_Archive'); - - //文件地址 - if (function_exists("html_entity_decode")) { - $source = html_entity_decode($source); - } - - //加密地址 - if ($settings->ap_encode) { - $playerOptions["soundFile"] = self::encodeSource($source); - } else { - $playerOptions["soundFile"] = $source; + //过滤html标签 + $atts = explode('|',trim(Typecho_Common::stripTags($matche['2']))); + $files = array_shift($atts); + + $pair = array(); + $data = array(); + foreach ($atts as $att) { + $pair = explode('=',$att); + $data[trim($pair['0'])] = trim($pair['1']); } - //生成实例 - $playerElementID = "audioplayer_".++self::$playerID; - $playerCode = '

'._t('播放此段音频需要Adobe Flash Player, 请点击下载最新版本并确认浏览器已开启JavaScipt支持','http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash&promoid=BIOW').'

'; - $playerCode .= ''; - - return $playerCode; + return self::getPlayer($files,$data,true); } /** - * 输出js嵌载方法 + * 输出播放器实例 * + * @param string $source 音频地址 + * @param array $playerOptions 参数设置 + * @param boolean $isCall 是否回调 * @return void */ - public static function playerjs() + public static function getPlayer($source,$playerOptions=array(),$isCall=false) { $options = Helper::options(); + $settings = $options->plugin('AudioPlayer'); $playerurl = $options->pluginUrl.'/AudioPlayer/assets/'; - echo ''; - echo "\n"; - echo ''; - echo "\n"; + $playerElementID = "audioplayer_".++self::$playerID; + + //url编码处理 + $source = html_entity_decode($source); + if (function_exists('iconv')) { + $address = iconv('gbk','utf-8',$source); + } + $playerOptions['soundFile'] = $settings->ap_encode ? self::encodeSource($address) : $address; + + $fallback = ''._t('播放此段音频需要Adobe Flash Player, 请点击下载最新版本并确认浏览器已开启JavaScipt支持','https://get.adobe.com/flashplayer/').''; + //不加密可html5 + if ($settings->ap_html5 && !$settings->ap_encode) { + $fallback = ''; + $sources = explode(',',$source); + foreach ($sources as $source) { + $fallback .= ''; + } + } + + //播放器实例代码 + $playerCode = ''; + $playerCode .= ''; + $playerCode .= '

'.$fallback.'

'; + $playerCode .= ''; + + //模版输出判断 + if ($isCall) { + return $playerCode; + } else { + echo $playerCode; + } } /** - * 输出配置参数 + * 输出插件设置 * * @return string */ - public static function getsets() + public static function getSets() { - //初始参数 - $options = array( - "width"=>"290", - "encode"=>false, - "animation"=>true, - "remaining"=>false, - "checkpolicy"=>true, - "noinfo"=>false, - "initialvolume"=>"60", - "buffer"=>"5", - "rtl"=>false, - "bg"=>"E5E5E5", - "text"=>"333333", - "leftbg"=>"CCCCCC", - "lefticon"=>"333333", - "volslider"=>"666666", - "voltrack"=>"FFFFFF", - "rightbg"=>"B4B4B4", - "rightbghover"=>"999999", - "righticon"=>"333333", - "righticonhover"=>"FFFFFF", - "track"=>"FFFFFF", - "loader"=>"009900", - "border"=>"CCCCCC", - "tracker"=>"DDDDDD", - "skip"=>"666666", - "transparentpagebg"=>true - ); - - //设置参数 - if (isset(Helper::options()->plugins['activated']['AudioPlayer'])) { - $settings = Helper::options()->plugin('AudioPlayer'); - $options["width"] = $settings->ap_width; - $options["encode"] = ($settings->ap_encode)?true:false; - $options["animation"] = ($settings->ap_animation)?false:true; - $options["remaining"] = ($settings->ap_remaining)?true:false; - $options["checkpolicy"] = ($settings->ap_checkpolicy)?true:false; - $options["noinfo"] = ($settings->ap_noinfo)?true:false; - $options["bg"] = substr($settings->ap_bgcolor,1); - $options["text"] = substr($settings->ap_textcolor,1); - $options["leftbg"] = substr($settings->ap_leftbgcolor,1); - $options["lefticon"] = substr($settings->ap_lefticoncolor,1); - $options["volslider"] = substr($settings->ap_volslidercolor,1); - $options["voltrack"] = substr($settings->ap_voltrackcolor,1); - $options["rightbg"] = substr($settings->ap_rightbgcolor,1); - $options["rightbghover"] = substr($settings->ap_righticonhovercolor,1); - $options["righticon"] = substr($settings->ap_righticoncolor,1); - $options["righticonhover"] = substr($settings->ap_rightbghovercolor,1); - $options["track"] = substr($settings->ap_trackcolor,1); - $options["loader"] = substr($settings->ap_loadercolor,1); - $options["border"] = substr($settings->ap_bordercolor,1); - $options["tracker"] = substr($settings->ap_trackercolor,1); - $options["skip"] = substr($settings->ap_skipcolor,1); + $options = Helper::options(); + //加载默认参数 + $ap_options = array( + 'width'=>'290', + 'initialvolume'=>'60', + 'buffer'=>'5', + 'animation'=>true, + 'encode'=>false, + 'remaining'=>false, + 'noinfo'=>false, + 'checkpolicy'=>true, + 'transparentpagebg'=>true, + 'rtl'=>false + ); + $colors = self::$Colors; + + //读取插件设置 + if (isset($options->plugins['activated']['AudioPlayer'])) { + $settings = $options->plugin('AudioPlayer'); + $ap_options['width'] = $settings->ap_width; + $ap_options['initialvolume'] = $settings->ap_initialvolume; + $ap_options['buffer'] = $settings->ap_buffer; + $ap_options['animation'] = $settings->ap_animation ? false : true; + $ap_options['encode'] = $settings->ap_encode ? true : false; + $ap_options['remaining'] = $settings->ap_remaining ? true : false; + $ap_options['noinfo'] = $settings->ap_noinfo ? true : false; + + //解析配色数据 + $colors = Json::decode($settings->ap_colors,true); + foreach ($colors as $key=>$color) { + $colors[$key] = substr($color,1); + } } - - return self::php2js($options); + return self::php2js(array_merge($ap_options,$colors)); } /** - * 配置参数转js + * 格式化配置参数 * * @param array $object * @return string */ private static function php2js($object) { - $js_options = '{'; - $separator = ""; - $real_separator = ","; + $separator = ''; + $real_separator = ','; + $js_options = '{'; foreach($object as $key=>$value) { - //布尔型格式 - if (is_bool($value)) $value = $value?"yes":"no"; - else if (in_array($key,array("soundFile","titles","artists"))) { - if (in_array($key,array("titles","artists"))) { - //标题艺术家信息 - if (function_exists("html_entity_decode")) { - $value = html_entity_decode($value); - } + //布尔型处理 + if (is_bool($value)) { + $value = $value ? 'yes' : 'no'; + } elseif (in_array($key,array('soundFile','titles','artists'))) { + //文本型处理 + if (in_array($key,array('titles','artists'))) { + $value = html_entity_decode($value); } $value = rawurlencode($value); } $js_options .= $separator.$key.':"'.$value.'"'; $separator = $real_separator; } - - $js_options .= "}"; + $js_options .= '}'; return $js_options; } @@ -401,17 +450,17 @@ private static function php2js($object) */ private static function encodeSource($string) { - $source = utf8_decode($string); - $ntexto = ""; - $codekey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"; + //对应swf解码修正 + $string = rawurlencode($string); + $ntexto = ''; + $codekey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'; for ($i=0;$itheme; $cssfile = __TYPECHO_ROOT_DIR__.__TYPECHO_THEME_DIR__.'/'.$theme.'/style.css'; - if (file_exists($cssfile)) { + if (is_file($cssfile)) { preg_match_all('/:[^:,;\{\}].*?#([abcdef1234567890]{3,6})/i',file_get_contents($cssfile),$matches); - return array_unique($matches[1]); + return array_unique($matches['1']); } - } /** @@ -444,19 +493,7 @@ private static function getThemeColors() { */ public static function widthformat($width) { - return preg_match("/^[0-9]+%?$/",$width); - } - - /** - * 判断颜色格式 - * - * @access public - * @param string $color - * @return boolean - */ - public static function colorformat($color) - { - return preg_match("/^#[0-9A-Fa-f]{6}$/",$color); + return preg_match('/^[0-9]+%?$/',$width); } } diff --git a/AudioPlayer/README.md b/AudioPlayer/README.md index 9082b412..008c1c80 100644 --- a/AudioPlayer/README.md +++ b/AudioPlayer/README.md @@ -1,4 +1,12 @@ -### AudioPlayer 1.2.0 for Typecho 0.9 +### Typecho音乐播放器插件AudioPlayer +2017年1月29日更新至**v1.2.5**: +- 修正摘要输出兼容feed提示 -详细使用说明和效果演示见blog发布地址: -####http://www.jzwalk.com/archives/net/audio-player-for-typecho \ No newline at end of file +2017年1月28日更新至**v1.2.4**: +- 重整结构优化嵌载模式效率 +- 修复短代码标签冲突等bug +- 支持配色重置与中文url加密 +- 增加缺省可使用HTML5播放 + +#### 详细说明与效果演示见blog发布地址: + > http://www.yzmb.me/archives/net/audio-player-for-typecho \ No newline at end of file diff --git a/AudioPlayer/assets/audio-player-admin.css b/AudioPlayer/assets/audio-player-admin.css index d54d3b60..2d68c11a 100644 --- a/AudioPlayer/assets/audio-player-admin.css +++ b/AudioPlayer/assets/audio-player-admin.css @@ -1,61 +1,69 @@ #ap_colorscheme { - position:relative; + position: relative; } + #ap_colorselector { - position:absolute; - top:130px; - left:165px; -} -#ap_colorselector input { - float: left; - margin: 0 5px 0 0; - padding: 2px; + position: absolute; + top: 42px; + left: 190px; } #ap_colorselector input { + float: left; + margin-right: 5px; padding: 2px; + width: 75px; + height: 23px; + text-transform : uppercase } #ap_colorsample { float: left; - width: 19px; - height: 19px; - border: 1px solid #000000; + width: 20px; + height: 20px; + border: 1px solid #444; background: #FFFFFF; } #ap_picker-btn { display: block; float: left; - height: 21px; + height: 23px; background: url(picker-icon.png) no-repeat left top; + padding-top: 1px; padding-left: 28px; - padding-top: 3px; - margin-left: 10px; - font-size: 11px; + margin-left: 13px; + font-size: 13px; cursor: pointer; - color: #0000FF; - text-decoration: underline; + color: #467B96; } #ap_themecolor-btn { display: block; float: left; - height: 21px; + height: 23px; background: url(theme-picker-icon.png) no-repeat left top; - padding-left: 28px; - padding-top: 3px; - margin-left: 10px; - font-size: 11px; + padding-top: 1px; + padding-left: 24px; + margin-left: 11px; + font-size: 13px; cursor: pointer; - color: #0000FF; - text-decoration: underline; + color: #467B96; +} + +#ap_resetcolor { + position: absolute; + bottom: 49px; + left: 132px; + height: 22px; + padding-bottom: 2px; + margin-bottom: 1.5px; } #ap_themecolor { display: none; width: 134px; - padding: 0 0 13px 0; + padding-bottom: 13px; float: left; background: url(thcpck-bottom.png) no-repeat left bottom; } @@ -64,14 +72,14 @@ display: block; text-indent: -9999px; height: 13px; - line-height: 0; - font-size: 0; background: url(thcpck-top.png) no-repeat left top; } #ap_themecolor ul { background: url(thcpck-slice.png) repeat-y left top; - padding: 1px 14px 1px 15px; + padding-top: 2px; + padding-right: 14px; + padding-left: 15px; float: left; width: 105px; margin: 0; @@ -84,7 +92,6 @@ float: left; width: 20px; height: 20px; - margin: 0 1px 1px 0; - line-height: 0; - font-size: 0; -} + margin-right: 1px; + margin-bottom: 1px; +} \ No newline at end of file diff --git a/AudioPlayer/assets/audio-player-admin.js b/AudioPlayer/assets/audio-player-admin.js index a3fd9c6f..3148d78d 100644 --- a/AudioPlayer/assets/audio-player-admin.js +++ b/AudioPlayer/assets/audio-player-admin.js @@ -1,41 +1,40 @@ (function ($) { - var timer, - fieldSelector, + var fieldSelector, + currentKey, colorField, colorPicker, colorSwatch, - currentColorField, player; - + var init = function () { - + + // 配色组件控制 fieldSelector = $("#ap_fieldselector"); + currentKey = fieldSelector.val(); colorField = $("#ap_colorvalue"); colorPicker = $("#ap_picker-btn"); colorSwatch = $("#ap_colorsample"); - currentColorField = $("#ap_" + fieldSelector.val() + "color"); - + fieldSelector.change(function () { - currentColorField = $("#ap_" + fieldSelector.val() + "color"); - colorField.val(currentColorField.val()); - colorPicker.ColorPickerSetColor(currentColorField.val()); - colorSwatch.css("background-color", currentColorField.val()); + currentKey = fieldSelector.val(); + colorField.val(colorDatas[currentKey]); + colorPicker.ColorPickerSetColor(colorDatas[currentKey]); + colorSwatch.css("background-color", colorDatas[currentKey]); }); - + colorField.keyup(function () { var color = colorField.val(); if (color.match(/#?[0-9a-f]{6}/i)) { - currentColorField.val(color); + colorDatas[currentKey] = color; colorSwatch.css("background-color", color); - colorPicker.ColorPickerSetColor(currentColorField.val()); + colorPicker.ColorPickerSetColor(colorDatas[currentKey]); updatePlayer(); } }); - + var themeColorPicker = $("#ap_themecolor"); if (themeColorPicker) { themeColorPicker.css("display", "none"); - //reorderThemeColors(); themeColorPickerBtn = $("#ap_themecolor-btn"); themeColorPickerBtn.click(function (evt) { themeColorPicker.css({ @@ -51,7 +50,7 @@ color = color.replace(/#(.)(.)(.)/, "#$1$1$2$2$3$3"); } colorField.val(color); - currentColorField.val(color); + colorDatas[currentKey] = color; colorSwatch.css("background-color", color); updatePlayer(); $("#ap_themecolor").css("display", "none"); @@ -61,99 +60,41 @@ themeColorPicker.hide(); }); } - + colorPicker.ColorPicker({ onChange: function (hsb, hex, rgb) { var color = "#" + hex; colorField.val(color); - currentColorField.val(color); + colorDatas[currentKey] = color; colorSwatch.css("background-color", color); updatePlayer(); }, - + onShow: function () { themeColorPicker.hide(); } }); - + selectColorField(); } - var tabClick = function (evt) { - var i; - var target = $(this); - var tab = target.parent(); - - evt.preventDefault(); - - if (tab.attr("class") == "current") { - return; - } - - tabs.removeClass("current"); - tab.addClass("current"); - - panels.css("display", "none"); - - var activeTabID = target.attr("href").replace(/[^#]*#/, ""); - - $("#" + activeTabID).css("display", "block"); - - if (activeTabID == "ap_panel-colour") { - timer = setTimeout(updatePlayer, 100); - } else if (timer) { - clearTimeout(timer); - } - } - var selectColorField = function () { - currentColorField = $("#ap_" + fieldSelector.val() + "color"); - colorField.val(currentColorField.val()); - colorPicker.ColorPickerSetColor(currentColorField.val()); - colorSwatch.css("background-color", currentColorField.val()); + currentKey = fieldSelector.val(); + colorField.val(colorDatas[currentKey]); + colorPicker.ColorPickerSetColor(colorDatas[currentKey]); + colorSwatch.css("background-color", colorDatas[currentKey]); } - + var updatePlayer = function () { player = audioplayer_swfobject.getObjectById("ap_demoplayer"); - - $(".typecho-option input[type=hidden]").each(function (i) { - player.SetVariable($(this).attr("name").replace(/ap_(.+)color/, "$1"), $(this).val().replace("#", "")); + + $.each(colorDatas, function(name,value){ + player.SetVariable(name, value.replace("#", "")); }); player.SetVariable("setcolors", 1); + // 更新json到隐藏域 + colorInput.val(JSON.stringify(colorDatas)); } - - /*var reorderThemeColors = function () { - var swatchList = this.themeColorPicker.getElement("ul"); - var swatches = swatchList.getElements("li"); - swatches.sort(function (a, b) { - var colorA = new Color(a.getProperty("title")); - var colorB = new Color(b.getProperty("title")); - colorA = colorA.rgbToHsb(); - colorB = colorB.rgbToHsb(); - if (colorA[2] < colorB[2]) { - return 1; - } - if (colorA[2] > colorB[2]) { - return -1; - } - return 0; - }); - swatches.each(function (swatch) { - swatch.injectTop(swatchList); - }); - }*/ - - var pickThemeColor = function (evt) { - var color = target.attr("title"); - if (color.length == 4) { - color = color.replace(/#(.)(.)(.)/, "#$1$1$2$2$3$3"); - } - $("#ap_colorvalue").val(color); - getCurrentColorField().val(color); - updatePlayer(); - $("#ap_picker-btn").ColorPickerSetColor(color); - $("ap_colorsample").css("background-color", color); - $("#ap_themecolor").css("display", "none"); - } + $(init); })(jQuery); \ No newline at end of file diff --git a/AudioPlayer/assets/audio-player.js b/AudioPlayer/assets/audio-player.js index 4f8b2bcd..c82921bc 100644 --- a/AudioPlayer/assets/audio-player.js +++ b/AudioPlayer/assets/audio-player.js @@ -1 +1,920 @@ -eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 15=7(){5 w="1I",M="2a",2b="3g 2E",2F="2G.2G",1u="3h/x-3i-3j",2c="3k",2d="3l",D=1J,A=1b,W=3m,2e=F,1v=[2H],X=[],1w=[],1c=[],1l,1x,1K,2f,16=F,1y=F,R,1L,2g=H,y=7(){5 b=C A.N!=w&&C A.17!=w&&C A.P!=w,u=W.3n.Y(),p=W.3o.Y(),2I=p?/D/.T(p):/D/.T(u),1d=p?/1d/.T(p):/1d/.T(u),1M=/1M/.T(u)?3p(u.1m(/^.*1M\\/(\\d+(\\.\\d+)?).*$/,"$1")):F,G=!+"\\3q",1n=[0,0,0],d=I;3(C W.2h!=w&&C W.2h[2b]==M){d=W.2h[2b].3r;3(d&&!(C W.2i!=w&&W.2i[1u]&&!W.2i[1u].3s)){2e=H;G=F;d=d.1m(/^.*\\s+(\\S+\\s+\\S+$)/,"$1");1n[0]=L(d.1m(/^(.*)\\..*$/,"$1"),10);1n[1]=L(d.1m(/^.*\\.(.*)\\s.*$/,"$1"),10);1n[2]=/[a-2J-Z]/.T(d)?L(d.1m(/^.*[a-2J-Z]+(.*)$/,"$1"),10):0}}B 3(C D.2K!=w){1N{5 a=3t 2K(2F);3(a){d=a.2j("$2L");3(d){G=H;d=d.1e(" ")[1].1e(",");1n=[L(d[0],10),L(d[1],10),L(d[2],10)]}}}1O(e){}}z{11:b,1f:1n,U:1M,G:G,D:2I,1d:1d}}(),3u=7(){3(!y.11){z}3((C A.V!=w&&A.V=="2k")||(C A.V==w&&(A.17("1P")[0]||A.1P))){1g()}3(!16){3(C A.1o!=w){A.1o("3v",1g,F)}3(y.G&&y.D){A.1Q(2d,7(){3(A.V=="2k"){A.2M(2d,1h.1i);1g()}});3(D==3w){(7(){3(16){z}1N{A.3x.3y("3z")}1O(e){1p(1h.1i,0);z}1g()})()}}3(y.U){(7(){3(16){z}3(!/3A|2k/.T(A.V)){1p(1h.1i,0);z}1g()})()}1R(1g)}}();7 1g(){3(16){z}1N{5 t=A.17("1P")[0].1q(P("2N"));t.Q.1r(t)}1O(e){z}16=H;5 a=1v.J;E(5 i=0;i0){E(5 i=0;i0){5 e=N(b);3(e){3(1A(X[i].2Q)&&!(y.U&&y.U<1V)){18(b,H);3(c){d.1j=H;d.2m=1B(b);c(d)}}B 3(X[i].2n&&1W()){5 f={};f.1X=X[i].2n;f.13=e.14("13")||"0";f.19=e.14("19")||"0";3(e.14("1Y")){f.2o=e.14("1Y")}3(e.14("2p")){f.2p=e.14("2p")}5 g={};5 p=e.17("2q");5 h=p.J;E(5 j=0;j\'}}1G.3O=\'<2a 2x="3P:3Q-3R-3S-3T-3U"\'+d+\'>\'+e+\'\';1w[1w.J]=a.O;r=N(a.O)}B{5 o=P(M);o.12("2l",1u);E(5 m K a){3(a[m]!=23.25[m]){3(m.Y()=="2o"){o.12("1Y",a[m])}B 3(m.Y()!="2x"){o.12(m,a[m])}}}E(5 n K b){3(b[n]!=23.25[n]&&n.Y()!="2r"){2Z(o,n,b[n])}}1G.Q.22(o,1G);r=o}}z r}7 2Z(a,b,c){5 p=P("2q");p.12("1C",b);p.12("2s",c);a.1q(p)}7 27(a){5 b=N(a);3(b&&b.1Z=="M"){3(y.G&&y.D){b.1k.21="1E";(7(){3(b.V==4){30(a)}B{1p(1h.1i,10)}})()}B{b.Q.1r(b)}}}7 30(a){5 b=N(a);3(b){E(5 i K b){3(C b[i]=="7"){b[i]=I}}b.Q.1r(b)}}7 N(a){5 b=I;1N{b=A.N(a)}1O(e){}z b}7 P(a){z A.P(a)}7 1s(a,b,c){a.1Q(b,c);1c[1c.J]=[a,b,c]}7 1A(a){5 b=y.1f,v=a.1e(".");v[0]=L(v[0],10);v[1]=L(v[1],10)||0;v[2]=L(v[2],10)||0;z(b[0]>v[0]||(b[0]==v[0]&&b[1]>v[1])||(b[0]==v[0]&&b[1]==v[1]&&b[2]>=v[2]))?H:F}7 1H(a,b,c,d){3(y.G&&y.1d){z}5 h=A.17("3V")[0];3(!h){z}5 m=(c&&C c=="3W")?c:"3X";3(d){R=I;1L=I}3(!R||1L!=m){5 s=P("1k");s.12("2l","3Y/3Z");s.12("40",m);R=h.1q(s);3(y.G&&y.D&&C A.28!=w&&A.28.J>0){R=A.28[A.28.J-1]}1L=m}3(y.G&&y.D){3(R&&C R.31==M){R.31(a,b)}}B{3(R&&C A.32!=w){R.1q(A.32(a+" {"+b+"}"))}}}7 18(a,b){3(!2g){z}5 v=b?"41":"2y";3(16&&N(a)){N(a).1k.2z=v}B{1H("#"+a,"2z:"+v)}}7 2A(s){5 a=/[\\\\\\"<>\\.;]/;5 b=a.42(s)!=I;z b&&C 33!=w?33(s):s}5 x=7(){3(y.G&&y.D){1J.1Q("43",7(){5 a=1c.J;E(5 i=0;i + is released under the MIT License +*/ + +var audioplayer_swfobject = function() { + + var UNDEF = "undefined", + OBJECT = "object", + SHOCKWAVE_FLASH = "Shockwave Flash", + SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash", + FLASH_MIME_TYPE = "application/x-shockwave-flash", + EXPRESS_INSTALL_ID = "SWFObjectExprInst", + ON_READY_STATE_CHANGE = "onreadystatechange", + + win = window, + doc = document, + nav = navigator, + + plugin = false, + domLoadFnArr = [main], + regObjArr = [], + objIdArr = [], + listenersArr = [], + storedAltContent, + storedAltContentId, + storedCallbackFn, + storedCallbackObj, + isDomLoaded = false, + isExpressInstallActive = false, + dynamicStylesheet, + dynamicStylesheetMedia, + autoHideShow = true, + + /* Centralized function for browser feature detection + - User agent string detection is only used when no good alternative is possible + - Is executed directly for optimal performance + */ + ua = function() { + var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF, + u = nav.userAgent.toLowerCase(), + p = nav.platform.toLowerCase(), + windows = p ? /win/.test(p) : /win/.test(u), + mac = p ? /mac/.test(p) : /mac/.test(u), + webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit + ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html + playerVersion = [0,0,0], + d = null; + if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) { + d = nav.plugins[SHOCKWAVE_FLASH].description; + if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+ + plugin = true; + ie = false; // cascaded feature detection for Internet Explorer + d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1"); + playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10); + playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10); + playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0; + } + } + else if (typeof win.ActiveXObject != UNDEF) { + try { + var a = new ActiveXObject(SHOCKWAVE_FLASH_AX); + if (a) { // a will return null when ActiveX is disabled + d = a.GetVariable("$version"); + if (d) { + ie = true; // cascaded feature detection for Internet Explorer + d = d.split(" ")[1].split(","); + playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; + } + } + } + catch(e) {} + } + return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac }; + }(), + + /* Cross-browser onDomLoad + - Will fire an event as soon as the DOM of a web page is loaded + - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/ + - Regular onload serves as fallback + */ + onDomLoad = function() { + if (!ua.w3) { return; } + if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically + callDomLoadFunctions(); + } + if (!isDomLoaded) { + if (typeof doc.addEventListener != UNDEF) { + doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false); + } + if (ua.ie && ua.win) { + doc.attachEvent(ON_READY_STATE_CHANGE, function() { + if (doc.readyState == "complete") { + doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee); + callDomLoadFunctions(); + } + }); + if (win == top) { // if not inside an iframe + (function(){ + if (isDomLoaded) { return; } + try { + doc.documentElement.doScroll("left"); + } + catch(e) { + setTimeout(arguments.callee, 0); + return; + } + callDomLoadFunctions(); + })(); + } + } + if (ua.wk) { + (function(){ + if (isDomLoaded) { return; } + if (!/loaded|complete/.test(doc.readyState)) { + setTimeout(arguments.callee, 0); + return; + } + callDomLoadFunctions(); + })(); + } + addLoadEvent(callDomLoadFunctions); + } + }(); + + function callDomLoadFunctions() { + if (isDomLoaded) { return; } + try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early + var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span")); + t.parentNode.removeChild(t); + } + catch (e) { return; } + isDomLoaded = true; + var dl = domLoadFnArr.length; + for (var i = 0; i < dl; i++) { + domLoadFnArr[i](); + } + } + + function addDomLoadEvent(fn) { + if (isDomLoaded) { + fn(); + } + else { + domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+ + } + } + + /* Cross-browser onload + - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/ + - Will fire an event as soon as a web page including all of its assets are loaded + */ + function addLoadEvent(fn) { + if (typeof win.addEventListener != UNDEF) { + win.addEventListener("load", fn, false); + } + else if (typeof doc.addEventListener != UNDEF) { + doc.addEventListener("load", fn, false); + } + else if (typeof win.attachEvent != UNDEF) { + addListener(win, "onload", fn); + } + else if (typeof win.onload == "function") { + var fnOld = win.onload; + win.onload = function() { + fnOld(); + fn(); + }; + } + else { + win.onload = fn; + } + } + + /* Main function + - Will preferably execute onDomLoad, otherwise onload (as a fallback) + */ + function main() { + if (plugin) { + testPlayerVersion(); + } + else { + matchVersions(); + } + } + + /* Detect the Flash Player version for non-Internet Explorer browsers + - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description: + a. Both release and build numbers can be detected + b. Avoid wrong descriptions by corrupt installers provided by Adobe + c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports + - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available + */ + function testPlayerVersion() { + var b = doc.getElementsByTagName("body")[0]; + var o = createElement(OBJECT); + o.setAttribute("type", FLASH_MIME_TYPE); + var t = b.appendChild(o); + if (t) { + var counter = 0; + (function(){ + if (typeof t.GetVariable != UNDEF) { + var d = t.GetVariable("$version"); + if (d) { + d = d.split(" ")[1].split(","); + ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; + } + } + else if (counter < 10) { + counter++; + setTimeout(arguments.callee, 10); + return; + } + b.removeChild(o); + t = null; + matchVersions(); + })(); + } + else { + matchVersions(); + } + } + + /* Perform Flash Player and SWF version matching; static publishing only + */ + function matchVersions() { + var rl = regObjArr.length; + if (rl > 0) { + for (var i = 0; i < rl; i++) { // for each registered object element + var id = regObjArr[i].id; + var cb = regObjArr[i].callbackFn; + var cbObj = {success:false, id:id}; + if (ua.pv[0] > 0) { + var obj = getElementById(id); + if (obj) { + if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match! + setVisibility(id, true); + if (cb) { + cbObj.success = true; + cbObj.ref = getObjectById(id); + cb(cbObj); + } + } + else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported + var att = {}; + att.data = regObjArr[i].expressInstall; + att.width = obj.getAttribute("width") || "0"; + att.height = obj.getAttribute("height") || "0"; + if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); } + if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); } + // parse HTML object param element's name-value pairs + var par = {}; + var p = obj.getElementsByTagName("param"); + var pl = p.length; + for (var j = 0; j < pl; j++) { + if (p[j].getAttribute("name").toLowerCase() != "movie") { + par[p[j].getAttribute("name")] = p[j].getAttribute("value"); + } + } + showExpressInstall(att, par, id, cb); + } + else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF + displayAltContent(obj); + if (cb) { cb(cbObj); } + } + } + } + else { // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content) + setVisibility(id, true); + if (cb) { + var o = getObjectById(id); // test whether there is an HTML object element or not + if (o && typeof o.SetVariable != UNDEF) { + cbObj.success = true; + cbObj.ref = o; + } + cb(cbObj); + } + } + } + } + } + + function getObjectById(objectIdStr) { + var r = null; + var o = getElementById(objectIdStr); + if (o && o.nodeName == "OBJECT") { + if (typeof o.SetVariable != UNDEF) { + r = o; + } + else { + var n = o.getElementsByTagName(OBJECT)[0]; + if (n) { + r = n; + } + } + } + return r; + } + + /* Requirements for Adobe Express Install + - only one instance can be active at a time + - fp 6.0.65 or higher + - Win/Mac OS only + - no Webkit engines older than version 312 + */ + function canExpressInstall() { + return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312); + } + + /* Show the Adobe Express Install dialog + - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 + */ + function showExpressInstall(att, par, replaceElemIdStr, callbackFn) { + isExpressInstallActive = true; + storedCallbackFn = callbackFn || null; + storedCallbackObj = {success:false, id:replaceElemIdStr}; + var obj = getElementById(replaceElemIdStr); + if (obj) { + if (obj.nodeName == "OBJECT") { // static publishing + storedAltContent = abstractAltContent(obj); + storedAltContentId = null; + } + else { // dynamic publishing + storedAltContent = obj; + storedAltContentId = replaceElemIdStr; + } + att.id = EXPRESS_INSTALL_ID; + if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; } + if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; } + doc.title = doc.title.slice(0, 47) + " - Flash Player Installation"; + var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn", + fv = "MMredirectURL=" + win.location.toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title; + if (typeof par.flashvars != UNDEF) { + par.flashvars += "&" + fv; + } + else { + par.flashvars = fv; + } + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work + if (ua.ie && ua.win && obj.readyState != 4) { + var newObj = createElement("div"); + replaceElemIdStr += "SWFObjectNew"; + newObj.setAttribute("id", replaceElemIdStr); + obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + obj.parentNode.removeChild(obj); + } + else { + setTimeout(arguments.callee, 10); + } + })(); + } + createSWF(att, par, replaceElemIdStr); + } + } + + /* Functions to abstract and display alternative content + */ + function displayAltContent(obj) { + if (ua.ie && ua.win && obj.readyState != 4) { + // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it, + // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work + var el = createElement("div"); + obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content + el.parentNode.replaceChild(abstractAltContent(obj), el); + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + obj.parentNode.removeChild(obj); + } + else { + setTimeout(arguments.callee, 10); + } + })(); + } + else { + obj.parentNode.replaceChild(abstractAltContent(obj), obj); + } + } + + function abstractAltContent(obj) { + var ac = createElement("div"); + if (ua.win && ua.ie) { + ac.innerHTML = obj.innerHTML; + } + else { + var nestedObj = obj.getElementsByTagName(OBJECT)[0]; + if (nestedObj) { + var c = nestedObj.childNodes; + if (c) { + var cl = c.length; + for (var i = 0; i < cl; i++) { + if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) { + ac.appendChild(c[i].cloneNode(true)); + } + } + } + } + } + return ac; + } + + /* Cross-browser dynamic SWF creation + */ + function createSWF(attObj, parObj, id) { + var r, el = getElementById(id); + if (ua.wk && ua.wk < 312) { return r; } + if (el) { + if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content + attObj.id = id; + } + if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML + var att = ""; + for (var i in attObj) { + if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries + if (i.toLowerCase() == "data") { + parObj.movie = attObj[i]; + } + else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword + att += ' class="' + attObj[i] + '"'; + } + else if (i.toLowerCase() != "classid") { + att += ' ' + i + '="' + attObj[i] + '"'; + } + } + } + var par = ""; + for (var j in parObj) { + if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries + par += ''; + } + } + el.outerHTML = '' + par + ''; + objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only) + r = getElementById(attObj.id); + } + else { // well-behaving browsers + var o = createElement(OBJECT); + o.setAttribute("type", FLASH_MIME_TYPE); + for (var m in attObj) { + if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries + if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword + o.setAttribute("class", attObj[m]); + } + else if (m.toLowerCase() != "classid") { // filter out IE specific attribute + o.setAttribute(m, attObj[m]); + } + } + } + for (var n in parObj) { + if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element + createObjParam(o, n, parObj[n]); + } + } + el.parentNode.replaceChild(o, el); + r = o; + } + } + return r; + } + + function createObjParam(el, pName, pValue) { + var p = createElement("param"); + p.setAttribute("name", pName); + p.setAttribute("value", pValue); + el.appendChild(p); + } + + /* Cross-browser SWF removal + - Especially needed to safely and completely remove a SWF in Internet Explorer + */ + function removeSWF(id) { + var obj = getElementById(id); + if (obj && obj.nodeName == "OBJECT") { + if (ua.ie && ua.win) { + obj.style.display = "none"; + (function(){ + if (obj.readyState == 4) { + removeObjectInIE(id); + } + else { + setTimeout(arguments.callee, 10); + } + })(); + } + else { + obj.parentNode.removeChild(obj); + } + } + } + + function removeObjectInIE(id) { + var obj = getElementById(id); + if (obj) { + for (var i in obj) { + if (typeof obj[i] == "function") { + obj[i] = null; + } + } + obj.parentNode.removeChild(obj); + } + } + + /* Functions to optimize JavaScript compression + */ + function getElementById(id) { + var el = null; + try { + el = doc.getElementById(id); + } + catch (e) {} + return el; + } + + function createElement(el) { + return doc.createElement(el); + } + + /* Updated attachEvent function for Internet Explorer + - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks + */ + function addListener(target, eventType, fn) { + target.attachEvent(eventType, fn); + listenersArr[listenersArr.length] = [target, eventType, fn]; + } + + /* Flash Player and SWF content version matching + */ + function hasPlayerVersion(rv) { + var pv = ua.pv, v = rv.split("."); + v[0] = parseInt(v[0], 10); + v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0" + v[2] = parseInt(v[2], 10) || 0; + return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false; + } + + /* Cross-browser dynamic CSS creation + - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php + */ + function createCSS(sel, decl, media, newStyle) { + if (ua.ie && ua.mac) { return; } + var h = doc.getElementsByTagName("head")[0]; + if (!h) { return; } // to also support badly authored HTML pages that lack a head element + var m = (media && typeof media == "string") ? media : "screen"; + if (newStyle) { + dynamicStylesheet = null; + dynamicStylesheetMedia = null; + } + if (!dynamicStylesheet || dynamicStylesheetMedia != m) { + // create dynamic stylesheet + get a global reference to it + var s = createElement("style"); + s.setAttribute("type", "text/css"); + s.setAttribute("media", m); + dynamicStylesheet = h.appendChild(s); + if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) { + dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1]; + } + dynamicStylesheetMedia = m; + } + // add style rule + if (ua.ie && ua.win) { + if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) { + dynamicStylesheet.addRule(sel, decl); + } + } + else { + if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) { + dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}")); + } + } + } + + function setVisibility(id, isVisible) { + if (!autoHideShow) { return; } + var v = isVisible ? "visible" : "hidden"; + if (isDomLoaded && getElementById(id)) { + getElementById(id).style.visibility = v; + } + else { + createCSS("#" + id, "visibility:" + v); + } + } + + /* Filter to avoid XSS attacks + */ + function urlEncodeIfNecessary(s) { + var regex = /[\\\"<>\.;]/; + var hasBadChars = regex.exec(s) != null; + return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s; + } + + /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only) + */ + var cleanup = function() { + if (ua.ie && ua.win) { + window.attachEvent("onunload", function() { + // remove listeners to avoid memory leaks + var ll = listenersArr.length; + for (var i = 0; i < ll; i++) { + listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]); + } + // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect + var il = objIdArr.length; + for (var j = 0; j < il; j++) { + removeSWF(objIdArr[j]); + } + // cleanup library's main closures to avoid memory leaks + for (var k in ua) { + ua[k] = null; + } + ua = null; + for (var l in audioplayer_swfobject) { + audioplayer_swfobject[l] = null; + } + audioplayer_swfobject = null; + }); + } + }(); + + return { + /* Public API + - Reference: http://code.google.com/p/swfobject/wiki/documentation + */ + registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) { + if (ua.w3 && objectIdStr && swfVersionStr) { + var regObj = {}; + regObj.id = objectIdStr; + regObj.swfVersion = swfVersionStr; + regObj.expressInstall = xiSwfUrlStr; + regObj.callbackFn = callbackFn; + regObjArr[regObjArr.length] = regObj; + setVisibility(objectIdStr, false); + } + else if (callbackFn) { + callbackFn({success:false, id:objectIdStr}); + } + }, + + getObjectById: function(objectIdStr) { + if (ua.w3) { + return getObjectById(objectIdStr); + } + }, + + embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) { + var callbackObj = {success:false, id:replaceElemIdStr}; + if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) { + setVisibility(replaceElemIdStr, false); + addDomLoadEvent(function() { + widthStr += ""; // auto-convert to string + heightStr += ""; + var att = {}; + if (attObj && typeof attObj === OBJECT) { + for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs + att[i] = attObj[i]; + } + } + att.data = swfUrlStr; + att.width = widthStr; + att.height = heightStr; + var par = {}; + if (parObj && typeof parObj === OBJECT) { + for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs + par[j] = parObj[j]; + } + } + if (flashvarsObj && typeof flashvarsObj === OBJECT) { + for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs + if (typeof par.flashvars != UNDEF) { + par.flashvars += "&" + k + "=" + flashvarsObj[k]; + } + else { + par.flashvars = k + "=" + flashvarsObj[k]; + } + } + } + if (hasPlayerVersion(swfVersionStr)) { // create SWF + var obj = createSWF(att, par, replaceElemIdStr); + if (att.id == replaceElemIdStr) { + setVisibility(replaceElemIdStr, true); + } + callbackObj.success = true; + callbackObj.ref = obj; + } + else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install + att.data = xiSwfUrlStr; + showExpressInstall(att, par, replaceElemIdStr, callbackFn); + return; + } + else { // show alternative content + setVisibility(replaceElemIdStr, true); + } + if (callbackFn) { callbackFn(callbackObj); } + }); + } + else if (callbackFn) { callbackFn(callbackObj); } + }, + + switchOffAutoHideShow: function() { + autoHideShow = false; + }, + + ua: ua, + + getFlashPlayerVersion: function() { + return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] }; + }, + + hasFlashPlayerVersion: hasPlayerVersion, + + createSWF: function(attObj, parObj, replaceElemIdStr) { + if (ua.w3) { + return createSWF(attObj, parObj, replaceElemIdStr); + } + else { + return undefined; + } + }, + + showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) { + if (ua.w3 && canExpressInstall()) { + showExpressInstall(att, par, replaceElemIdStr, callbackFn); + } + }, + + removeSWF: function(objElemIdStr) { + if (ua.w3) { + removeSWF(objElemIdStr); + } + }, + + createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) { + if (ua.w3) { + createCSS(selStr, declStr, mediaStr, newStyleBoolean); + } + }, + + addDomLoadEvent: addDomLoadEvent, + + addLoadEvent: addLoadEvent, + + getQueryParamValue: function(param) { + var q = doc.location.search || doc.location.hash; + if (q) { + if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark + if (param == null) { + return urlEncodeIfNecessary(q); + } + var pairs = q.split("&"); + for (var i = 0; i < pairs.length; i++) { + if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) { + return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1))); + } + } + } + return ""; + }, + + // For internal usage only + expressInstallCallback: function() { + if (isExpressInstallActive) { + var obj = getElementById(EXPRESS_INSTALL_ID); + if (obj && storedAltContent) { + obj.parentNode.replaceChild(storedAltContent, obj); + if (storedAltContentId) { + setVisibility(storedAltContentId, true); + if (ua.ie && ua.win) { storedAltContent.style.display = "block"; } + } + if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); } + } + isExpressInstallActive = false; + } + } + }; +}(); +var AudioPlayer = function () { + var instances = []; + var groups = {}; + var activePlayers = {}; + var playerURL = ""; + var defaultOptions = {}; + var currentVolume = -1; + var requiredFlashVersion = "9"; + + function getPlayer(playerID) { + if (document.all && !window[playerID]) { + for (var i = 0; i < document.forms.length; i++) { + if (document.forms[i][playerID]) { + return document.forms[i][playerID]; + break; + } + } + } + return document.all ? window[playerID] : document[playerID]; + } + + function addListener (playerID, type, func) { + getPlayer(playerID).addListener(type, func); + } + + return { + setup: function (url, options) { + playerURL = url; + defaultOptions = options; + if (audioplayer_swfobject.hasFlashPlayerVersion(requiredFlashVersion)) { + audioplayer_swfobject.switchOffAutoHideShow(); + audioplayer_swfobject.createCSS("p.audioplayer_container span", "visibility:hidden;height:24px;overflow:hidden;padding:0;border:none;"); + } + }, + + getPlayer: function (playerID) { + return getPlayer(playerID); + }, + + addListener: function (playerID, type, func) { + addListener(playerID, type, func); + }, + + embed: function (elementID, options) { + var instanceOptions = {}; + var key; + + var flashParams = {}; + var flashVars = {}; + var flashAttributes = {}; + + // Merge default options and instance options + for (key in defaultOptions) { + instanceOptions[key] = defaultOptions[key]; + } + for (key in options) { + instanceOptions[key] = options[key]; + } + + if (instanceOptions.transparentpagebg == "yes") { + flashParams.bgcolor = "#FFFFFF"; + flashParams.wmode = "transparent"; + } else { + if (instanceOptions.pagebg) { + flashParams.bgcolor = "#" + instanceOptions.pagebg; + } + flashParams.wmode = "opaque"; + } + + flashParams.menu = "false"; + + for (key in instanceOptions) { + if (key == "pagebg" || key == "width" || key == "transparentpagebg") { + continue; + } + flashVars[key] = instanceOptions[key]; + } + + flashAttributes.name = elementID; + flashAttributes.style = "outline: none"; + + flashVars.playerID = elementID; + + audioplayer_swfobject.embedSWF(playerURL, elementID, instanceOptions.width.toString(), "24", requiredFlashVersion, false, flashVars, flashParams, flashAttributes); + + instances.push(elementID); + + if (options.group) { + groups[elementID] = options.group; + } + }, + + syncVolumes: function (playerID, volume) { + if (groups[playerID]) return; + currentVolume = volume; + for (var i = 0; i < instances.length; i++) { + if (!groups[instances[i]] && instances[i] != playerID) { + getPlayer(instances[i]).setVolume(currentVolume); + } + } + }, + + activate: function (playerID, info) { + for (var activePlayerID in activePlayers) { + if (activePlayerID == playerID) { + continue; + } + if (groups[playerID] != groups[activePlayerID]) { + this.close(activePlayerID); + continue; + } + if (!(groups[playerID] || groups[activePlayerID])) { + this.close(activePlayerID); + } + } + activePlayers[playerID] = 1; + }, + + load: function (playerID, soundFile, titles, artists) { + getPlayer(playerID).load(soundFile, titles, artists); + }, + + close: function (playerID) { + getPlayer(playerID).close(); + if (playerID in activePlayers) { + delete activePlayers[playerID]; + } + }, + + open: function (playerID, index) { + if (index == undefined) { + index = 1; + } + getPlayer(playerID).open(index == undefined ? 0 : index-1); + }, + + getVolume: function (playerID) { + return currentVolume; + } + + } + +}(); diff --git a/AudioPlayer/assets/player.swf b/AudioPlayer/assets/player.swf index bf05ee55..31275821 100644 Binary files a/AudioPlayer/assets/player.swf and b/AudioPlayer/assets/player.swf differ