diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..060f495 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "extends": [ + "wikimedia/mediawiki", + "wikimedia/client/common", + "wikimedia/language/es2020" + ], + "globals": { + "require": "readonly", + "module": "readonly", + "OO": "readonly" + }, + "rules": { + "space-before-function-paren": "off", + "no-jquery/no-global-selector": "off", + "vars-on-top": "off", + "one-var": "off", + "no-use-before-define": "off", + "mediawiki/class-doc": "off", + "mediawiki/no-nodelist-unsupported-methods": "off", + "jsdoc/require-param-type": "off" + } +} diff --git a/.gitignore b/.gitignore index f4bae1c..d75bba6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /node_modules/ composer.lock package-lock.json +.idea/ diff --git a/composer.json b/composer.json index 3695c41..c8a9f05 100644 --- a/composer.json +++ b/composer.json @@ -29,5 +29,10 @@ "minus-x fix .", "phpcbf" ] + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/extension.json b/extension.json index 930158a..c722dd3 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "NetworkNotice", - "version": "3.2.1", + "version": "3.3.0", "author": [ "Tephus", "[https://fo-nttax.de Alex Winkler]" @@ -26,10 +26,14 @@ "HookHandlers": { "Main": { "class": "\\Liquipedia\\Extension\\NetworkNotice\\Hooks\\MainHookHandler" + }, + "Schema": { + "class": "\\Liquipedia\\Extension\\NetworkNotice\\Hooks\\SchemaHookHandler" } }, "Hooks": { "BeforePageDisplay": "Main", + "LoadExtensionSchemaUpdates": "Schema", "LPExtensionMenu": [ "Liquipedia\\Extension\\NetworkNotice\\Hooks\\LegacyHooks::onLPExtensionMenu" ], @@ -48,6 +52,9 @@ "styles": [ "styles/ext.networknotice.Notice.less" ], + "scripts": [ + "scripts/ext.networknotice.Notice.js" + ], "position": "bottom" } }, diff --git a/i18n/en.json b/i18n/en.json index 8bda416..f4e2a0c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -17,6 +17,7 @@ "networknotice-delete-network-notice-heading": "Delete network notice", "networknotice-preview-heading": "Preview", "networknotice-delete-network-notice-deletion-heading": "Confirm deletion", + "networknotice-close-button": "Close notification", "networknotice-create-notice-desc": "Creates network notices (site notices) that can be displayed network wide, with more features than standard site notices.", "networknotice-create-notice-label-label": "Label:", @@ -56,9 +57,9 @@ "networknotice-button-delete-label": "delete", "networknotice-text-false-label": "false", "networknotice-text-true-label": "true", - + "networknotice-success-updated": "Network notice successfully updated!", "networknotice-success-created": "Network notice successfully created!", "lpextmenu-networknotice": "Network Notice" -} \ No newline at end of file +} diff --git a/package.json b/package.json index f03a704..1450360 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "MIT", "private": true, "devDependencies": { + "eslint-config-wikimedia": "*", "stylelint-config-wikimedia": "*" }, "scripts": { diff --git a/resources/scripts/ext.networknotice.Notice.js b/resources/scripts/ext.networknotice.Notice.js new file mode 100644 index 0000000..d1c2be5 --- /dev/null +++ b/resources/scripts/ext.networknotice.Notice.js @@ -0,0 +1,59 @@ +( function ( window, document ) { + 'use strict'; + + const LOCAL_STORAGE_KEY = 'networknotice'; + + function init() { + if ( 'localStorage' in window ) { + document.querySelectorAll( '[data-component="network-notice"]' ).forEach( function( notice ) { + const key = notice.dataset.id; + if ( isInStorage( key ) ) { + notice.classList.add( 'd-none' ); + } else { + const closeButton = notice.querySelector( + '[data-component="network-notice-close-button"]' + ); + closeButton.onclick = function() { + notice.classList.add( 'd-none' ); + putIntoStorage( key ); + }; + } + } ); + } + } + + function getItemsFromStorage() { + const items = localStorage.getItem( LOCAL_STORAGE_KEY ); + try { + return items ? JSON.parse( items ) : []; + } catch ( e ) { + return [ ]; + } + } + + function putIntoStorage( key ) { + const items = getItemsFromStorage(); + if ( !items.includes( key ) ) { + items.push( key ); + localStorage.setItem( LOCAL_STORAGE_KEY, JSON.stringify( items ) ); + } + } + + function isInStorage( key ) { + const items = getItemsFromStorage(); + return items.includes( key ); + } + + /** + * Check on document readyState + */ + if ( document.readyState === 'complete' ) { + init(); + } else { + document.addEventListener( 'readystatechange', () => { + if ( document.readyState === 'complete' ) { + init(); + } + } ); + } +}( window, document ) ); diff --git a/resources/styles/ext.networknotice.Notice.less b/resources/styles/ext.networknotice.Notice.less index 2059eac..5d28365 100644 --- a/resources/styles/ext.networknotice.Notice.less +++ b/resources/styles/ext.networknotice.Notice.less @@ -1,171 +1,93 @@ -.networknotice { - margin-top: 0.1875rem; - display: block; - text-align: center; - padding: 0.3125rem 1.5rem 0.3125rem 0.3125rem; - margin-bottom: 0.4375rem; - border-left-width: 0.3125rem; - border-left-style: solid; +.network-notice { + min-height: 3rem; + display: grid; + grid-template-columns: auto 3rem; + box-shadow: 0 0.0625rem 0.25rem 0 rgba( 0, 0, 0, 0.12 ); + border-radius: 0.5rem; position: relative; + padding: 0 0 0 1.5rem; + font-size: 0.875rem; + align-items: center; + background-color: #ffffff; // default for Bruinen & LakesideView light theme + margin-bottom: 0.5rem; - a, - a:visited, - a:hover, - a:visited:hover { - color: inherit; - font-weight: bold; - text-decoration: underline; + @media ( min-width: 768px ) { + grid-template-columns: auto 3.75rem; } - .make-networknotice-skin( - ~'default', - var( --network-notice-default-color, #444444 ), - var( --network-notice-default-background-color, #ccccff ), - var( --network-notice-default-border-color, #0000ff ) - ); - - .make-networknotice-skin( - ~'inverse', - var( --network-notice-inverse-color, #ffffff ), - var( --network-notice-inverse-background-color, #333333 ), - var( --network-notice-inverse-border-color, #000000 ) - ); - - .make-networknotice( - ~'red', - var( --network-notice-red-color, #444444 ), - var( --network-notice-red-background-color, #ffcccc ), - var( --network-notice-red-border-color, #ff0000 ) - ); - - .make-networknotice( - ~'green', - var( --network-notice-green-color, #444444 ), - var( --network-notice-green-background-color, #ccffcc ), - var( --network-notice-green-border-color, #00ff00 ) - ); + .theme--dark & { + background-color: #26292d; + } - .make-networknotice( - ~'blue', - var( --network-notice-blue-color, #444444 ), - var( --network-notice-blue-background-color, #ccccff ), - var( --network-notice-blue-border-color, #0000ff ) - ); + &::before { + content: ''; + width: 0.5rem; + top: 0; + bottom: 0; + left: 0; + position: absolute; + background-color: var( --clr-wiki-primary ); + border-radius: 0.5rem 0 0 0.5rem; + } - .make-networknotice( - ~'lightgrey', - var( --network-notice-lightgrey-color, #444444 ), - var( --network-notice-lightgrey-background-color, #eeeeee ), - var( --network-notice-lightgrey-border-color, #000000 ) - ); + &__content { + word-break: break-word; - .make-networknotice( - ~'darkgrey', - var( --network-notice-darkgrey-color, #444444 ), - var( --network-notice-darkgrey-background-color, #cccccc ), - var( --network-notice-darkgrey-border-color, #333333 ) - ); + &-wrapper { + border-right: 0.0625rem solid rgba( 0, 0, 0, 0.16 ); + margin: 0.5rem 0; + padding-right: 1rem; + display: flex; + align-items: center; + grid-column: 1; - .make-networknotice( - ~'yellow', - var( --network-notice-yellow-color, #444444 ), - var( --network-notice-yellow-background-color, #ffffcc ), - var( --network-notice-yellow-border-color, #ffff00 ) - ); + .theme--dark & { + border-right-color: rgba( 255, 255, 255, 0.16 ); + } + } - .make-networknotice( - ~'purple', - var( --network-notice-purple-color, #444444 ), - var( --network-notice-purple-background-color, #ffccff ), - var( --network-notice-purple-border-color, #ff00ff ) - ); + &-icon { + display: inline-flex; + width: 1.5rem; + height: 1.5rem; + align-items: center; + justify-content: center; + margin-right: 0.75rem; + font-size: 1.125rem; + opacity: 0.7; - .make-networknotice( - ~'turquoise', - var( --network-notice-turquoise-color, #444444 ), - var( --network-notice-turquoise-background-color, #ccffff ), - var( --network-notice-turquoise-border-color, #00ffff ) - ); -} + @media ( max-width: 768px ) { + display: none; + } + } + } -html.theme--light .networknotice { - --network-notice-default-color: var( --clr-wiki-on-primary-container ); - --network-notice-default-background-color: var( --clr-wiki-primary-container ); - --network-notice-default-border-color: var( --clr-wiki-on-primary-container ); - --network-notice-inverse-color: var( --clr-wiki-on-primary ); - --network-notice-inverse-background-color: var( --clr-wiki-primary ); - --network-notice-inverse-border-color: var( --clr-wiki-on-primary-container ); - --network-notice-red-color: var( --clr-semantic-negative-10 ); - --network-notice-red-background-color: var( --clr-semantic-negative-90 ); - --network-notice-red-border-color: var( --clr-semantic-negative-40 ); - --network-notice-green-color: var( --clr-semantic-positive-10 ); - --network-notice-green-background-color: var( --clr-semantic-positive-90 ); - --network-notice-green-border-color: var( --clr-semantic-positive-40 ); - --network-notice-blue-color: var( --clr-sapphire-90 ); - --network-notice-blue-background-color: var( --clr-sapphire-10 ); - --network-notice-blue-border-color: var( --clr-sapphire-90 ); - --network-notice-lightgrey-color: var( --clr-on-surface-variant ); - --network-notice-lightgrey-background-color: var( --clr-surface-variant ); - --network-notice-lightgrey-border-color: var( --clr-on-surface-variant ); - --network-notice-darkgrey-color: var( --clr-surface-variant ); - --network-notice-darkgrey-background-color: var( --clr-on-surface-variant ); - --network-notice-darkgrey-border-color: var( --clr-surface-variant ); - --network-notice-yellow-color: var( --clr-sun-10 ); - --network-notice-yellow-background-color: var( --clr-sun-90 ); - --network-notice-yellow-border-color: var( --clr-sun-40 ); - --network-notice-purple-color: var( --clr-redviolet-10 ); - --network-notice-purple-background-color: var( --clr-redviolet-90 ); - --network-notice-purple-border-color: var( --clr-redviolet-40 ); - --network-notice-turquoise-color: var( --clr-elm-10 ); - --network-notice-turquoise-background-color: var( --clr-elm-80 ); - --network-notice-turquoise-border-color: var( --clr-elm-40 ); -} + &__close-button { + width: 2.75rem; + height: 2.75rem; + display: flex; + align-items: center; + justify-content: center; + margin: 0 0.625rem 0 0.375rem; + grid-column: 2; + cursor: pointer; + border-radius: 0.25rem; + transition: background-color 0.2s ease-in-out; -html.theme--dark .networknotice { - --network-notice-default-color: #ffffff; - --network-notice-default-background-color: var( --clr-primary-30 ); - --network-notice-default-border-color: var( --clr-primary-30 ); - --network-notice-inverse-color: var( --clr-primary-10 ); - --network-notice-inverse-background-color: var( --clr-primary-80 ); - --network-notice-inverse-border-color: var( --clr-primary-80 ); - --network-notice-red-color: #ffffff; - --network-notice-red-background-color: var( --clr-semantic-negative-20 ); - --network-notice-red-border-color: var( --clr-semantic-negative-20 ); - --network-notice-green-color: #ffffff; - --network-notice-green-background-color: var( --clr-semantic-positive-20 ); - --network-notice-green-border-color: var( --clr-semantic-positive-20 ); - --network-notice-blue-color: #ffffff; - --network-notice-blue-background-color: var( --clr-sapphire-20 ); - --network-notice-blue-border-color: var( --clr-sapphire-20 ); - --network-notice-lightgrey-color: var( --clr-moon-20 ); - --network-notice-lightgrey-background-color: var( --clr-moon-90 ); - --network-notice-lightgrey-border-color: var( --clr-moon-90 ); - --network-notice-darkgrey-color: #ffffff; - --network-notice-darkgrey-background-color: var( --clr-moon-20 ); - --network-notice-darkgrey-border-color: var( --clr-moon-20 ); - --network-notice-yellow-color: var( --clr-sun-90 ); - --network-notice-yellow-background-color: var( --clr-sun-10 ); - --network-notice-yellow-border-color: var( --clr-sun-10 ); - --network-notice-purple-color: var( --clr-redviolet-90 ); - --network-notice-purple-background-color: var( --clr-redviolet-10 ); - --network-notice-purple-border-color: var( --clr-redviolet-10 ); - --network-notice-turquoise-color: var( --clr-elm-80 ); - --network-notice-turquoise-background-color: var( --clr-elm-10 ); - --network-notice-turquoise-border-color: var( --clr-elm-10 ); -} + @media ( min-width: 768px ) { + width: 2rem; + height: 2rem; + margin: 0 1rem 0 0.75rem; + } -.make-networknotice-skin( @theme, @color, @background, @border ) { - &.networknotice-@{theme} { - color: @color; - background-color: @background; - border-left-color: @border; - } -} + @media ( hover: hover ) { + &:hover { + background-color: rgba( 0, 0, 0, 0.16 ); -.make-networknotice( @theme, @color, @background, @border ) { - &.networknotice-@{theme} { - color: @color; - background-color: @background; - border-left-color: @border; + .theme--dark & { + background-color: rgba( 255, 255, 255, 0.16 ); + } + } + } } } diff --git a/sql/3_3_0.sql b/sql/3_3_0.sql new file mode 100644 index 0000000..1b2ea69 --- /dev/null +++ b/sql/3_3_0.sql @@ -0,0 +1 @@ +ALTER TABLE `networknotice` DROP `style`; diff --git a/networknotice.sql b/sql/networknotice.sql similarity index 66% rename from networknotice.sql rename to sql/networknotice.sql index 3cb3c33..8e08a08 100644 --- a/networknotice.sql +++ b/sql/networknotice.sql @@ -1,23 +1,12 @@ -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -SET time_zone = "+00:00"; - - --- -------------------------------------------------------- --- Table structure for table `networknotice` --- - CREATE TABLE IF NOT EXISTS `networknotice` ( `notice_id` int(11) NOT NULL AUTO_INCREMENT, `label` tinyblob NOT NULL, `wiki` blob NOT NULL, `namespace` tinyblob NOT NULL, `notice_text` blob NOT NULL, - `style` tinyblob NOT NULL, `category` blob NOT NULL, `prefix` blob NOT NULL, `action` blob NOT NULL, `disabled` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`notice_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=binary; - - diff --git a/src/Colors.php b/src/Colors.php deleted file mode 100644 index a526f22..0000000 --- a/src/Colors.php +++ /dev/null @@ -1,28 +0,0 @@ -addModuleStyles( 'ext.networknotice.Notice' ); + $out->addModules( 'ext.networknotice.Notice' ); } /** @@ -57,7 +57,6 @@ public function onSiteNoticeAfter( &$siteNotice, $skin ) { 'networknotice', [ 'notice_text', - 'style', 'category', 'prefix', 'notice_id' @@ -75,7 +74,6 @@ public function onSiteNoticeAfter( &$siteNotice, $skin ) { if ( empty( $row->category ) ) { $siteNotice .= NoticeHtml::getNoticeHTML( $out, - $row->style, $row->notice_text, $row->notice_id ); @@ -84,7 +82,6 @@ public function onSiteNoticeAfter( &$siteNotice, $skin ) { if ( $category === $row->category ) { $siteNotice .= NoticeHtml::getNoticeHTML( $out, - $row->style, $row->notice_text, $row->notice_id ); diff --git a/src/Hooks/SchemaHookHandler.php b/src/Hooks/SchemaHookHandler.php new file mode 100644 index 0000000..71198c8 --- /dev/null +++ b/src/Hooks/SchemaHookHandler.php @@ -0,0 +1,25 @@ +getMainConfig(); + $db = $updater->getDB(); + if ( !$db->tableExists( $config->get( 'DBname' ) . '.networknotice', __METHOD__ ) ) { + $updater->addExtensionTable( 'networknotice', __DIR__ . '/../../sql/networknotice.sql' ); + } + if ( $db->fieldExists( $config->get( 'DBname' ) . '.networknotice', 'style' ) ) { + $updater->dropExtensionField( 'networknotice', 'style', __DIR__ . '/../../sql/3_3_0.sql' ); + } + } + +} diff --git a/src/NoticeHtml.php b/src/NoticeHtml.php index 83c05ff..3a1fb44 100644 --- a/src/NoticeHtml.php +++ b/src/NoticeHtml.php @@ -9,28 +9,73 @@ class NoticeHtml { /** * Generate the Html for out notice * @param OutputPage $outputPage - * @param string $style * @param string $text * @param string $id * @return string Html for our notice */ - public static function getNoticeHTML( $outputPage, $style, $text, $id = '0' ) { - $classes = [ - 'networknotice', - 'networknotice-' . $style, - ]; - $attributes = [ - 'id' => 'networknotice-' . $id, - 'data-id' => $id, - 'class' => implode( ' ', $classes ), - ]; - - $element = Html::rawElement( + public static function getNoticeHTML( $outputPage, $text, $id = '0' ) { + $closeButtonText = wfMessage( 'networknotice-close-button' )->text(); + + $closeButtonIcon = Html::rawElement( + 'i', + [ + 'class' => 'fa fa-times', + ] + ); + + $closeButton = Html::rawElement( + 'div', + [ + 'class' => 'network-notice__close-button', + 'aria-label' => $closeButtonText, + 'data-component' => 'network-notice-close-button', + 'title' => $closeButtonText, + 'tabindex' => '0', + ], + $closeButtonIcon + ); + + $contentIconElement = Html::rawElement( + 'i', + [ + 'class' => 'fa fa-info-circle', + ] + ); + + $contentIconWrapper = Html::rawElement( + 'div', + [ + 'class' => 'network-notice__content-icon', + ], + $contentIconElement + ); + + $contentDiv = Html::rawElement( + 'div', + [ + 'class' => 'network-notice__content', + ], + $outputPage->parseInlineAsInterface( $text, false ) + ); + + $contentWrapper = Html::rawElement( + 'div', + [ + 'class' => 'network-notice__content-wrapper', + ], + $contentIconWrapper . $contentDiv + ); + + return Html::rawElement( 'div', - $attributes, - $outputPage->parseInlineAsInterface( $text, false ) + [ + 'id' => 'network-notice-' . $id, + 'data-id' => $id, + 'class' => 'network-notice', + 'data-component' => 'network-notice' + ], + $contentWrapper . $closeButton ); - return $element; } } diff --git a/src/SpecialPage/SpecialNetworkNotice.php b/src/SpecialPage/SpecialNetworkNotice.php index 401ed27..382d062 100644 --- a/src/SpecialPage/SpecialNetworkNotice.php +++ b/src/SpecialPage/SpecialNetworkNotice.php @@ -4,7 +4,6 @@ use Html; use HTMLForm; -use Liquipedia\Extension\NetworkNotice\Colors; use Liquipedia\Extension\NetworkNotice\NoticeHtml; use Status; use Wikimedia\Rdbms\ILoadBalancer; @@ -62,7 +61,6 @@ public function execute( $par ) { $formDefaults[ 'NoticeId' ] = $row->notice_id; $formDefaults[ 'NoticeLabel' ] = $row->label; $formDefaults[ 'NoticeText' ] = $row->notice_text; - $formDefaults[ 'NoticeStyle' ] = $row->style; $formDefaults[ 'NoticeNamespace' ] = $row->namespace; $formDefaults[ 'NoticeWiki' ] = $row->wiki; $formDefaults[ 'NoticeCategory' ] = $row->category; @@ -105,20 +103,6 @@ public function execute( $par ) { 'required' => true, 'default' => ( $isEdit ? $formDefaults[ 'NoticeText' ] : '' ) ]; - $formDescriptor[ 'NoticeStyle' ] = [ - 'type' => 'select', - 'label-message' => 'networknotice-create-notice-style-label', - 'help-message' => 'networknotice-create-notice-style-helper', - 'required' => true, - 'options' => ( static function ( $colors ) { - $dropDown = []; - foreach ( $colors as $color ) { - $dropDown[ $color ] = $color; - } - return $dropDown; - } )( Colors::getNoticeColors() ), - 'default' => $isEdit ? $formDefaults[ 'NoticeStyle' ] : '' - ]; $formDescriptor[ 'NoticeNamespace' ] = [ 'type' => 'text', 'label-message' => 'networknotice-create-notice-namespace-label', @@ -229,8 +213,6 @@ public function execute( $par ) { foreach ( $currentnotices as $row ) { $preContent = $this->msg( 'networknotice-create-notice-text-label' )->text() . ' ' . $row->notice_text . "\n"; - $preContent .= $this->msg( 'networknotice-create-notice-style-label' )->text() - . ' ' . $row->style . "\n"; if ( $row->wiki ) { $preContent .= $this->msg( 'networknotice-create-notice-wiki-label' )->text() . ' ' . $row->wiki . "\n"; @@ -315,7 +297,6 @@ public function createNetworkNoticeCB( $formData ) { $output->addHTML( NoticeHtml::getNoticeHTML( $output, - $formData[ 'NoticeStyle' ], $formData[ 'NoticeText' ] ) ); @@ -323,7 +304,6 @@ public function createNetworkNoticeCB( $formData ) { $vars = [ 'label' => $formData[ 'NoticeLabel' ], 'notice_text' => $formData[ 'NoticeText' ], - 'style' => $formData[ 'NoticeStyle' ], 'namespace' => $formData[ 'NoticeNamespace' ], 'wiki' => $formData[ 'NoticeWiki' ], 'category' => $formData[ 'NoticeCategory' ], @@ -380,7 +360,6 @@ private function getNetworkNotices() { 'notice_id', 'label', 'notice_text', - 'style', 'wiki', 'category', 'prefix', @@ -403,7 +382,6 @@ private function getNetworkNoticeById( $id ) { 'notice_id', 'label', 'notice_text', - 'style', 'wiki', 'category', 'prefix',