Архив метки: html

Символ рубля на сайте

Шел конец 2020 года, а мы всё еще не умеем штатно отображать символ рубля. Вот одно из решений:

1) Устанавливаем вот этот шрифт в css:

@font-face { 
    font-family: "rouble";
    src: url("/fonts/rouble.otf") format("opentype");
}
.rub { font-family: "rouble"; }

2) В коде прописываем:

<span class="rub">i</span>

Android WebView: не работает выбор файла на странице в теге input type=»file»

Неожиданно обнаружилось что в странице загружаемой в виджет webview  не работаю инпуты файлов. Т.е. при нажатии кнопки браузер не реагирует от слова никак. Как оказалось при дальнейших раскопках, Google подразумевает, что обработку файлов «вы берете на себя».

Решение:

public class MainActivity extends AppCompatActivity {
    private WebView mbrowser;
    private ValueCallback<Uri> mUploadMessage;
    public ValueCallback<Uri[]> uploadMessage;
    public static final int REQUEST_SELECT_FILE = 100;
    private final static int FILECHOOSER_RESULTCODE = 1;
...
...
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (requestCode == REQUEST_SELECT_FILE) {
                if (uploadMessage == null) return;
                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
                uploadMessage = null;
            }
        }
        else if (requestCode == FILECHOOSER_RESULTCODE) {
            if (null == mUploadMessage) return;
            Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
...
...
        mbrowser=(WebView) findViewById(R.id.main_webview);
        mbrowser.getSettings().setJavaScriptEnabled(true); // разрешен javascript
        mbrowser.getSettings().setAppCacheEnabled(false); // разрешон кэш
        mbrowser.getSettings().setDatabaseEnabled(true); // хранение данных во встроенной БД в браузере
        mbrowser.getSettings().setDomStorageEnabled(true);
       // mbrowser.getSettings().setSupportZoom(true); // зум
        mbrowser.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); // разрешать открывать окна
        //mbrowser.getSettings().setBuiltInZoomControls(true); // приблизить/удалить
        mbrowser.getSettings().setGeolocationEnabled(true); // разрешаем геолокацию
        mbrowser.setWebChromeClient(new WebChromeClient() {
                                        @Override
                                        public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
                                            callback.invoke(origin, true, false);
                                        }
                                        // For 3.0+ Devices (Start)
                                        // onActivityResult attached before constructor
                                        protected void openFileChooser(ValueCallback uploadMsg, String acceptType) {
                                            mUploadMessage = uploadMsg;
                                            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                                            i.addCategory(Intent.CATEGORY_OPENABLE);
                                            i.setType("image/*");
                                            startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
                                        }
                                        // For Lollipop 5.0+ Devices
                                        public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                                            if (uploadMessage != null) {
                                                uploadMessage.onReceiveValue(null);
                                                uploadMessage = null;
                                            }
                                            uploadMessage = filePathCallback;
                                            Intent intent = null;
                                            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                                                intent = fileChooserParams.createIntent();
                                            }
                                            try {
                                                startActivityForResult(intent, REQUEST_SELECT_FILE);
                                            } catch (ActivityNotFoundException e) {
                                                uploadMessage = null;
                                                return false;
                                            }
                                            return true;
                                        }
                                        //For Android 4.1 only
                                        protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
                                            mUploadMessage = uploadMsg;
                                            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                                            intent.addCategory(Intent.CATEGORY_OPENABLE);
                                            intent.setType("image/*");
                                            startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
                                        }
                                        protected void openFileChooser(ValueCallback<Uri> uploadMsg) {
                                            mUploadMessage = uploadMsg;
                                            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                                            i.addCategory(Intent.CATEGORY_OPENABLE);
                                            i.setType("image/*");
                                            startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
                                        }

        });

Пробуем ReactJS

Если честно, пока не представляю, что можно сделать с ReactJS, что нельзя сделать удобно и понятно при помощи Jquery+PHP. Но решил таки попробовать. Итак, что такое ReactJS — фактически это надстройка над JavaScript написанная на языке JavaScript. Т.е. всё что написано на ReactJS — компилируется или «на лету» при помощи babel в javascript или при выкладывании в «продакт» и далее подключается вызовом обычного JavaScript.

Чтобы не разделять «продакт» «девелоп» и не возиться с бабелом, я у себя настроил один из вариантов, а именно в косоли висит запущеный скрипт-компилятор, который мониторит изменения файлов в папке src и при изменении чего-либо, компилирует файл в папку js. Соответственно всегда имеем «продакт».

Что нужно сделать чтоб начать пользоваться ReactJS:

1) Поставить NodeJS и ReactJS на компьютере где разрабатываем (компиляция кода ReactJS в JavaScript происходит при помощи его):

apt install nodejs
npm install babel-cli@6 babel-preset-react-app@3

2) Ставим npx — утилита которая позволяет запускать npm пакеты

npm install -g npx

3) Зпаускаем в консоли что-типа:

npx babel --watch src --out-dir js --presets react-app/prod

В моем случае все скрипты из папки src компилируются в папку js

В итоге html страница может выглядеть так:

<!DOCTYPE html>
<html>    
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <head>
        <meta charset="UTF-8">
        <title id="rj_title"></title>
    </head>
    <body id="rj_body">
        <div id="root"></div>
        <script src="js/test.js"></script>
    </body>
</html>

а файл src/test.js так:

const name='Павел Игоревич';
const element = <h1>Привет {name}!</h1>;
ReactDOM.render(
  element,
  document.getElementById('root')
);

В браузере выведет:

Простой способ сохранить файл по нажатию кнопки на странице (HTML)

Задача: по нажатию кнопки на странице, чтоб вызывался диалог сохранения файла и собственно сохранялся произвольный файл с сервера.

Решение:

В коде html страницы упоминаем скрытую форму:

<form method="post" action="inc/csvExport.php">
	<input type="hidden" name="csvBuffer" id="csvBuffer" value="" />
</form>

Добавляем туда же обработчик нажатия вида:

    $("#viewwork").click(function(){       
            document.forms[0].method='POST';
            document.forms[0].action=save_file.php; 
            document.forms[0].target='_self';
            document.forms[0].submit();  	    	    
       return false;
    });

Ну код на сервере для:

save_file.php:

<?php

// Данный код создан и распространяется по лицензии GPL v3
// Изначальный автор данного кода - Грибов Павел
// http://грибовы.рф

$ex= "1;2;3;4;5;6;7";
 header("Content-type: application/msexcel");
    header("Accept-Ranges: bytes");
    header("Content-Length: " . strlen($ex));
    header("Content-Disposition: attachment; filename=rep_by_addr.csv");

?>

csvExport.php:

<?php

// Данный код создан и распространяется по лицензии GPL v3
// Изначальный автор данного кода - Грибов Павел
// http://грибовы.рф

header('Content-type: application/vnd.ms-excel');
if (isset($_GET["csv"])==true){
    header("Content-Disposition: attachment; filename=file.csv");
} else {
    header("Content-Disposition: attachment; filename=file.xls");
};
header("Pragma: no-cache");

$buffer = $_POST['csvBuffer'];

try{
    echo $buffer;
}catch(Exception $e){

}
?>

Потоковое видео rtsp на сайте

Задача: есть IP камера вещающая по протоколу rtsp. В html5 стандарте, этот протокол не поддерживается. Ни один флеш и javascript плеер, его так-же не воспроизводят. С плагинами в браузер — бред.

Решение: при помощи ngnix конвертируем видео в удобовариваемый формат. Решение стырено с: http://conture.by/post/1552#more-1552

Для начала необходимые пакеты:

apt-get install libpcre3 libpcre3-dev libssl-dev gcc build-essential unzip rtmpdump

Устанавливать nginx надо не через apt-get, а из исходников.

wget http://conture.by/wp-content/uploads/2015/06/nginx-1.8.0.tar.gz
tar -xzvf nginx-1.8.0.tar.gz
wget http://conture.by/wp-content/uploads/2015/06/nginx-rtmp-module-master.zip
unzip nginx-rtmp-module-master.zip -d nginx-rtmp-module-master
wget http://conture.by/wp-content/uploads/2015/06/ffmpeg_nginx.zip
unzip ffmpeg_nginx.zip -d /bin
chmod 777 /bin/ffmpeg_nginx
cd nginx-1.8.0
./configure --prefix=/usr --add-module=../nginx-rtmp-module-master/arut-nginx-rtmp-module-f62a083/ --pid-path=/var/run/nginx.pid --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-http_ssl_module
make
make install
cp ../nginx-rtmp-module-master/arut-nginx-rtmp-module-f62a083/stat.xsl /etc/nginx/stat.xsl

Далее открываем конфиг nginx расположенный /etc/nginx/nginx.conf и правим под себя. У меня он следующий…

user www-data;
worker_processes 4; # воркеры по количеству ядер процессора
pid /run/nginx.pid;
error_log  /var/log/nginx/nginx_error.log debug;
env PATH;
events {
    worker_connections 768;
}

http {
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen 88;

        # rtmp stat

        location /stat {
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        }

        location /stat.xsl {
            # you can move stat.xsl to a different location
            root /etc/nginx/;
        }

        location / {
            rtmp_control all;
        }


        error_page   500 502 503 504  /50x.html;

        location = /50x.html {
            root   html;
        }
    }
}

# RTMP proxy
rtmp {
    access_log /var/log/nginx/rtmp_access.log;
    server {
        listen 1935;
        ping 30s;
        notify_method get;
        # ретрансляция без звука
        application camera_1 {
            live on;
            exec_pull ffmpeg_nginx -i http://192.168.2.40:8000/71-camera1 -vcodec copy -f flv -an rtmp://localhost:1935/camera_1/live 2>>/var/log/nginx/ffmpeg_camera_1.log;
       }
       # конвертируем в меньшее разрешение без звука
        application cam_1 {
            live on;
            exec_pull ffmpeg_nginx -i http://192.168.2.40:8000/71-camera1 -threads 2 -f flv -r 25 -s 800x600 -an rtmp://localhost:1935/cam_1/live 2>>/var/log/nginx/ffmpeg_cam1.log;
       }
       # и ещё один поток...
        application infochan {
           live on;
           exec_pull ffmpeg_nginx -i http://192.168.2.40:8000/70-infokanal -threads 2 -f flv -r 25 -s 800x600 -an rtmp://localhost:1935/infochan/live 2>>/var/log/nginx/ffmpeg_infochan.log;
      }
    }
}

Проверяем корректность нашего конфига nginx:

root@kubuntu:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@kubuntu:~#

Если всё ок, то запускаем nginx:

service nginx start

Проверяем льётся ли что-нибудь на порт 1935. Выхлоп должен идти прямо в консоль.

rtmpdump -r "rtmp://127.0.0.1:1935/camera_1/live" -v
rtmpdump -r "rtmp://127.0.0.1:1935/cam_1/live" -v
rtmpdump -r "rtmp://127.0.0.1:1935/infochan/live" -v

Если есть выхлоп, то гуд. Приступаем к установке Flash-плеера на сайт. Качаем и распаковываем папку архива на сайт.
Содержимое html-страницы где будет встроен плеер должно иметь следующую структуру:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script src="/jwplayer/jwplayer.js" type="text/javascript"></script>
<div id="contain">Loading the player ...</div>
<script>
jwplayer("contain").setup({
  autostart:!0,
  height:600,
  width:800,
  modes:[{
   type:"flash",
   src:"/jwplayer/player.swf",
   config:{file:"live",streamer:"rtmp://внешний_ip_сервера_rtmp/infochan",provider:"rtmp"}
  }]
});
</script>