Перейти к публикации
View in the app

A better way to browse. Learn more.

Дизайн и модификация Invision Community

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Фильтр по играм

Опубликовано:

Здравствуйте. Мне необходимо реализовать фильтр по картам, функционал весь готов, осталось вывести правильно сам фильтр.

 

И так, структура БД: http://prntscr.com/llhs1f

 

Мне нужно получить уникальные botid и gamename, так как они дублируются.

 

Получил список уникальных botid: http://prntscr.com/llht3e это основа, по которой должен формироваться фильтр, id чекбоксов будет равен этому полю.

 

Как мне получить имя игры?

 

Т.е должно быть что-то вроде: select gamename from stats_gamelist where botid='' and id='здесь первый попавшийся автоинкримент, чтобы вывести только одно значение';

 

Наверно ничего не понятно....!!!!@@@###$$$

Рекомендованные сообщения

Опубликовано:
  • Автор

Нужны, просто я переделываю приложение с нуля и решил сделать более грамотно его. Сейчас дошел до фильтра и подумал, что у этих функций более правильное решение. AJAX планирую сделать через файл, который обновляет ЛС, на его основе точнее. Ну куки работают сейчас и тут, с этим всё норм.

 

На этом эта мне надо сделать, чтобы контент обновлялся при нажатии на фильтр, потом уже буду ковырять AJAX.

 

Сейчас файл такой:

 

Чуть позже уберу всё лишнее тут.

 

/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
* ips.forum.flow.js - Flow filter controller
*
* Author: Matt Mecham, certainly not Rikki Tissier (yet)
*/
;( function($, _, undefined){
"use strict";

ips.controller.register('wc3.front.games.runningGamesFilter', {

	_ids: [],
	_button: null,

	initialize: function () {
		this.on( 'click', '[data-node-id]', this.toggleFilters );

		this.setup();
	},

	/**
	 * Um, set up...
	 */
	setup: function () {
		/* Populate forum IDs */
		var _ids = ips.utils.url.getParam( 'botId' );

		var self = this;

		if ( ! _.isUndefined( _ids ) ) {
			/* Check URL */
			this._ids = decodeURIComponent( _ids ).split(',');
		} else if( ! _.isUndefined( ips.utils.cookie.get('runningGames_botIds') ) ) {
			/* Check local storage */
			this._ids = ips.utils.cookie.get('runningGames_botIds').split(',');
		}

		if( _.isObject( this._ids ) && _.size( this._ids ) ){
			_.each( this._ids, function (val, key) {
				if ( val ) {
					self.childSelect( val, true );
				}
			});
		}

		this._button = $('body').find('[data-role="fluidForumMobileDesc"]');
		this._updateButtonText();
	},

	/**
	 * Event handler for toggling a filter
	 *
	 * @param 	{event} 	e 	Event object
	 * @returns {void}
	 */
	toggleFilters: function (e) {
		e.preventDefault();
		var link = $( e.currentTarget );
		var id = link.attr('data-node-id');
		var parentId = link.attr('data-parent-id');
		var hasChildren = link.attr('data-has-children');

		if ( _.indexOf( this._ids, id ) == -1 ) {
			/* Does not exist, so add it */
			this.childSelect( id, false );

		} else {
			/* Exists, so remove it */
			this.childUnselect( id );
		}

		this._updateButtonText();

		$( document ).trigger( 'updateTableURL', { botId: _.uniq( _.values( this._ids ) ).join(',') } );
	},

	/**
	 * Is item selected
	 *
	 */
	isSelected: function(id) {
		return this.scope.find('[data-node-id="' + id + '"]').hasClass('cForumMiniList_selected') ? true : false;
	},

	/**
	 * Select a child
	 *
	 */
	childSelect: function(id, skipChildren) {
		Debug.log("Select child: " + id );
		this._ids.push( id );
		var node = this.scope.find('[data-node-id="' + id + '"]');
		node.addClass('cForumMiniList_selected');
		var parentId = node.attr('data-parent-id');

		/* Mark any children, but we do not need to keep individual row markings */
		if ( skipChildren === false && ( node.attr('data-has-children') || id == parentId ) ) {
			var self = this;
			_.each( this.scope.find('[data-parent-id="' + id + '"]'), function( v, k ) {
				var _cId = $(v).attr('data-node-id');
				if ( _cId != id ) {
					self.childSelect( _cId, false );
				}
			} );
		}

		this.updateCookie();
	},

	/**
	 * Unselect a child
	 *
	 */
	childUnselect: function(id) {
		Debug.log("UNselect child: " + id );
		/* Remove marking */
		this.scope.find('[data-node-id="' + id + '"]').removeClass('cForumMiniList_selected');

		/* Remove from local storage and id stack */
		this._ids = _.without( this._ids, id );
		this.updateCookie();

		/* Check for children of this and unselect those too */
		var self = this;
		_.each( this.scope.find('[data-parent-id="' + id + '"]'), function( v, k ) {
			var _cId = $(v).attr('data-node-id');
			if ( _cId != id ) {
				self.childUnselect( _cId );
			}
		} );

		/* And we always need to unselect the category */
		this.parentUnselect( this.scope.find('[data-node-id="' + id + '"]').closest('[data-category]').find('[data-node-id]').first().attr('data-node-id') );
	},

	/**
	 * Select a parent
	 *
	 */
	parentSelect: function(parentId) {
		Debug.log("Select parent: " + parentId );
		/* Mark category and children as selected */
		this.scope.find('[data-node-id="' + parentId + '"]').addClass('cForumMiniList_selected');

		/* Remove children from the arrays as PHP handles this */
		var self = this;
		_.each( this.scope.find('[data-parent-id="' + parentId + '"]'), function( v, k ) {
			var _cId = $(v).attr('data-node-id');

			if ( _cId != parentId ) {
				self.childUnselect( _cId );
			}
		} );
	},

	/**
	 * Unselect a parent
	 *
	 */
	parentUnselect: function(parentId) {
		Debug.log("UNselect parent: " + parentId );
		/* Unselect parent as marked */
		var node = this.scope.find('[data-node-id="' + parentId + '"]');
		node.removeClass('cForumMiniList_selected');

		this._ids = _.without( this._ids, parentId );
		this.updateCookie();

		/* Off up the tree we go */
		Debug.log( "Looking for parent ID " + node.attr('data-parent-id') );
		var self = this;
		_.each( this.scope.find('[data-node-id="' + node.attr('data-parent-id') + '"]'), function( v, k ) {
			var _cId = $(v).attr('data-node-id');
			if ( _cId != parentId ) {
				Debug.log( "Found " + _cId );
				self.parentUnselect( _cId );
			}
		} );
	},

	/**
	 * Update the cookie
	 */
	updateCookie: function(id) {
		var cookie = _.uniq( _.values( this._ids ) ).join(',');
		Debug.log("Updating cookie: " + cookie );

		ips.utils.cookie.set('runningGames_botIds', cookie, true);
	},

	/**
	 * Updates the mobile button text based on selected forums
	 *
	 * @param		{event}		e			The submit event
	 * @param		{element} 	elem 		The element this widget is being created on
	 * @returns		{void}
	 */
	_updateButtonText: function () {
		var blobs = this.scope.find('.cForumMiniList_blob');
		var selectedBlobRows = blobs.filter( function () {
			if( $( this ).closest('.cForumMiniList_selected').length ){
				return true;
			}
			return false;
		});
		var text = '';

		// If the counts are the same, we know we've selected all of them
		if( blobs.length == selectedBlobRows.length || selectedBlobRows.length === 0 ){
			text = ips.getString('topicsFromAllForums');
		} else {
			text = ips.pluralize( ips.getString( 'topicsFromXForums' ), selectedBlobRows.length );
		}

		this._button.text( text );
	}
});
}(jQuery, _));

Опубликовано:
  • Автор

Еще хочу спросить, модуль который сейчас делаю, активные игры можно передавать с помощью вебсокета, я мало про него знаю, знаю что он с JS работает ну и у меня есть готовый код в принципе. В чем разница между вебсокетом и обычными данными ?

Опубликовано:

Правильно вывел кол-во игр?

Мне кажется тут еще можно использовать группировку сразу в запросе по botid. За одно и приплюсовать там totalplayers и получить готовый результат.

 

->select( 'botid, gamename, SUM(totalplayers) as players, COUNT(*) as games', 'stats_gamelist', NULL, 'botid ASC', NULL, 'botid' )

Опубликовано:
  • Автор

@siv1987 Спасибо, позже рассмотрю эту инфу, башка не варит уже )))

 

@newbie Я разобрался, правда пол движка пришлось перекопать, ну ладно...

 

Этим параметром обновляются результаты, у меня не получилось только за счет HTML структуры превратить это в рабочий вариант, нужна всё равно форма от Table.

$( document ).trigger( 'updateTableURL', { botId: _.uniq( _.values( this._ids ) ).join(',') } );

 

Нужно реализовать что-то вроде:

 

$( document ).trigger( 'contentChange', [ this.scope ] );

 

где this.scope - функция html обновления, помогите плиз.

Опубликовано:

Спасибо, позже рассмотрю эту инфу, башка не варит уже )))

		foreach( \IPS\Db::i('wc3')->select( 'botid, gamename, SUM(totalplayers) as players, COUNT(*) as games', 'stats_gamelist', NULL, 'botid ASC', NULL, 'botid' ) as $bot )
		{
			$bot['gamename'] = trim( current( explode('#', $bot['gamename']) ) );
			static::$cachedBotlist[ $bot['botid'] ] = $bot;
		}

Опубликовано:
  • Автор

Ура, у меня получилось обновить страничку при нажатии, осталось сделать обновление только таблицы ))))

 

 

		var rows = this.scope.find('[data-role="tableRows"]');

		if( !rows.length ){
			window.location = this._baseURL;
			return;
		}


		$( document ).trigger( 'contentChange', [ this.scope ] );

Опубликовано:

window.location/reload это вообще топор. А почему не использовать ajax запрос? В ипс есть удобный апи для работы с ним если муторно разбиратся с таблицами форума.

Опубликовано:

            foreach( \IPS\Db::i('wc3')->select( 'botid, gamename, SUM(totalplayers) as players, COUNT(*) as games', 'stats_gamelist', NULL, 'botid ASC', NULL, 'botid' ) as $bot )
            {
                $bot['gamename'] = trim( current( explode('#', $bot['gamename']) ) );
                static::$cachedBotlist[ $bot['botid'] ] = $bot;
            }

Забыл предложить вариант с GROUP BY

Предложенный код может не работать из-за ONLY_FULL_GROUP_BY (в mysql 5.7 включен по умолчанию)

Можно сделать так

->select( 'botid, MIN(gamename) as gamename, SUM(totalplayers) as players, COUNT(*) as games'

Опубликовано:

Зачем Вам такая js-портянка нужна.

Если у Вас не таблица, то смысл переделывать под таблицу только из-за того, что есть какой-то js-код

 

Повторюсь. У Вас же был js-код для подобного. Возьмите и перепишите его.

Опубликовано:
  • Автор

У меня не было обновления при клике. Сейчас мне нужно только это сделать, под таблицы не обязательно, просто нужно вот эту функцию правильно изменить: http://ipbskins.ru/forum/topic15808.html/page__view__findpost__p__105904 код небольшой и простой, там ничего лишнего сейчас нет, просто он более правильный и другой.

 

Т.е тут выбор чекбоксов, обновление их из куков и URL, запись в куки, немного для мобилок, с этим всё норм. Мне нудно вот по ссылке выше в коде сделать обновление моей таблице ПО НАЖАТИЮ на фильтр.

 

/**
*
* ips.games.runningGamesFilter.js - Bot filter controller
*
*/
;( function($, _, undefined){
"use strict";

ips.controller.register('wc3.front.games.runningGamesFilter', {

	_ids: [],
	_button: null,

	initialize: function () {
		this.on( 'click', '[data-bot-id]', this.toggleFilters );
		this.setup();
	},

	/**
	 * Um, set up...
	 */
	setup: function () {
		/* Populate forum IDs */
		var _ids = ips.utils.url.getParam( 'botId' );

		var self = this;

		/* BotId */
		if ( ! _.isUndefined( _ids ) ) {
			/* Проверка айди в строке URL */
			this._ids = decodeURIComponent( _ids ).split(',');
		} else if( ! _.isUndefined( ips.utils.cookie.get('runningGames_botIds') ) ) {
			/* Проверка айди в куках */
			this._ids = ips.utils.cookie.get('runningGames_botIds').split(',');
		}

		if( _.isObject( this._ids ) && _.size( this._ids ) ){
			_.each( this._ids, function (val, key) {
				if ( val ) {
					self.botSelect( val, true );
				}
			});
		}

		this._button = $('body').find('[data-role="fluidForumMobileDesc"]');
		this._updateButtonText();
	},

	/**
	 * Event handler for toggling a filter
	 *
	 * @param 	{event} 	e 	Event object
	 * @returns {void}
	 */
	toggleFilters: function (e) {
		e.preventDefault();
		var link = $( e.currentTarget );
		var id = link.attr('data-bot-id');

		if ( _.indexOf( this._ids, id ) == -1 ) {
			/* Does not exist, so add it */
			this.botSelect( id, false );

		} else {
			/* Exists, so remove it */
			this.botUnselect( id );
		}

		this._updateButtonText();

		$( document ).trigger( 'updateTableURL', { botId: _.uniq( _.values( this._ids ) ).join(',') } );
	},

	/**
	 * Is item selected
	 *
	 */
	isSelected: function(id) {
		return this.scope.find('[data-bot-id="' + id + '"]').hasClass('cForumMiniList_selected') ? true : false;
	},

	/**
	 * Select a child
	 *
	 */
	botSelect: function(id) {
		Debug.log("Выбран бот: " + id );
		this._ids.push( id );
		var node = this.scope.find('[data-bot-id="' + id + '"]');
		node.addClass('cForumMiniList_selected');

		this.updateCookie();
	},

	/**
	 * Unselect a child
	 *
	 */
	botUnselect: function(id) {
		Debug.log("Удален бот: " + id );
		/* Remove marking */
		this.scope.find('[data-bot-id="' + id + '"]').removeClass('cForumMiniList_selected');

		/* Remove from local storage and id stack */
		this._ids = _.without( this._ids, id );
		this.updateCookie();
	},

	/**
	 * Обновление куков
	 */
	updateCookie: function(id) {
		var cookie = _.uniq( _.values( this._ids ) ).join(',');
		Debug.log("Обновление куков: " + cookie );

		ips.utils.cookie.set('runningGames_botIds', cookie, true);
	},

	/**
	 * Updates the mobile button text based on selected forums
	 *
	 * @param		{event}		e			The submit event
	 * @param		{element} 	elem 		The element this widget is being created on
	 * @returns		{void}
	 */
	_updateButtonText: function () {
		var blobs = this.scope.find('.cForumMiniList_blob');
		var selectedBlobRows = blobs.filter( function () {
			if( $( this ).closest('.cForumMiniList_selected').length ){
				return true;
			}
			return false;
		});
		var text = '';

		// If the counts are the same, we know we've selected all of them
		if( blobs.length == selectedBlobRows.length || selectedBlobRows.length === 0 ){
			text = ips.getString('topicsFromAllForums');
		} else {
			text = ips.pluralize( ips.getString( 'topicsFromXForums' ), selectedBlobRows.length );
		}

		this._button.text( text );
	}

});
}(jQuery, _));

Опубликовано:

Мне нудно вот по ссылке выше в коде сделать обновление моей таблице ПО НАЖАТИЮ на фильтр.

Делайте ajax-запрос и обновляйте html

Опубликовано:
  • Автор

Так, помогите заменить содержимое при автоматическом обновлении, что-то не получается. http://prntscr.com/lly1r4

 

	/**
	 * Processes an ajax response
	 *
	 * @param	{object} 	response 	 	Server response
	 * @returns {void} 
	 */
	_handleResponse: function (response) {
		try {
			// If auto-polling is now disabled, stop everything
			if( response.error && response.error == 'auto_polling_disabled' ){
				this._stopPolling( true );
				return;
			}






			$('#gamelistTable').find('ol').html( response['html'] );








		} catch (err) {
			this._stopPolling( true );
			return;
		}
	},

Опубликовано:

И где тут ajax-запрос? Тут уже какой-то ответ разбирается.

Опубликовано:
  • Автор

response выводит шаблон который нужно из модуля > ajax, с этим всё в порядке, шаблон в логах выводится, но не заменяется в таблице.

 

	/**
	 * The main method to check notification status
	 * Checks in localstorage to see if the last poll was < 20s ago
	 *
	 * @returns {void}
	 */
	_checkNotifications: function () {

		// If our window is inactive, increase the count
		if( document[ ips.utils.events.getVisibilityProp() ] ){
			if( this._windowInactivePoll >= 3 && this._pollMultiplier === 1 ){ // 0-3 minutes @ 60s poll
				if( this._debugPolling ){
					Debug.log( "runningGames: Polled over 3 minutes, increasing multiplier to 2");
				}
				this._pollMultiplier = 2;
				this._setInterval( this._pollTimeout * this._pollMultiplier );
			} else if( this._windowInactivePoll >= 7 && this._pollMultiplier === 2 ) { // 4-11 minutes @ 120s poll
				if( this._debugPolling ){
					Debug.log( "runningGames: Polled over 10 minutes, increasing multiplier to 3");
				}
				this._pollMultiplier = 3;
				this._setInterval( this._pollTimeout * this._pollMultiplier );
			} else if( this._windowInactivePoll >= 25 && this._pollMultiplier === 3 ) { // > 60 mins stop
				if( this._debugPolling ){
					Debug.log( "runningGames: Polled over 60 mins, stopping polling");
				}
				this._stopPolling();
				return;
			}

			this._windowInactivePoll++;
		}

		// We send our currently-displayed bubble count to the backend
		// to find out if there's any change in number
		var dataToSend = { dataToSend };

		this._doAjaxRequest( dataToSend );

	},

	/**
	 * Calls the backend to get new notification data
	 *
	 * @param	{object} 	dataToSend 	 	Object containing current message and notification counts
	 * @returns {void} 
	 */
	_doAjaxRequest: function (dataToSend) {
		var self = this;
		var url = ips.getSetting( 'baseURL' ) + '?app=wc3&module=games&controller=runningGames&do=ajax';

		if( this._debugPolling ){
			Debug.log("runningGames: sending ajax request");
		}

		// We'll update the timestamp before polling so that other windows
		// don't start polling before this one is finished
		//this._updateTimestamp();

		// We do need to poll, it's been more than 20s
		this._ajaxObj = ips.getAjax()( url, {
			data: dataToSend
		})
			.done( _.bind( this._handleResponse, this ) )
			.fail( function () {
				self._stopPolling(true);
				Debug.error("Problem polling for new notifications; stopping.");
			});
	},


	/**
	 * Processes an ajax response
	 *
	 * @param	{object} 	response 	 	Server response
	 * @returns {void} 
	 */
	_handleResponse: function (response) {
		try {
			// If auto-polling is now disabled, stop everything
			if( response.error && response.error == 'auto_polling_disabled' ){
				this._stopPolling( true );
				return;
			}
			var html = '';
			var table = $('#gamelistTable');
			var tableBody = table.find('ol');

			if( this._debugPolling ){
				tableBody.replaceWith(response);
				Debug.log("Update");
			}

		} catch (err) {
			this._stopPolling( true );
			return;
		}
	},

Опубликовано:
  • Автор

Так заработало.

 

this.scope.find('ol').html( response );

 

Сейчас начну удалять всё не нужное, по коду всё понятно. Что скажете в целом? А и еще, я думаю при нажатии на фильтр вызывать вот эту функцию, которая обновляет автоматом. Да?

 

Еще по поводу функционала хотелось бы сказать, в той версии было просто обновление таблицы + вывод таймера. Сейчас я имею обновление таблицы когда окно активно, остановку обновления когда окно не активно, различные тайминговые функции для этого, если час окно не активно - поллинг останавливается и т.д и т.п.

Изменено пользователем TemKa_SD

Создайте аккаунт или войдите в него для комментирования

Сейчас на странице 0

  • Нет пользователей, просматривающих эту страницу.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.