Greasy Fork

Notify

Notification sytem library

目前为 2018-05-16 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/40236/597782/Notify.js

"use strict";

/*
* Options:
* - title   ( string, optional, if value is "" not show.)
*
* - content ( string, required)
*
* - type    ( int, NORMAL/SUCCESS/WARING/ERROR)
*           ( optional, default is NORMAL )
*
* - mode    ( string, toast/modal/snackbar)
*           ( optional, default is toast )
*
* - delay   ( boolean, optional )
*           ( default is 1000 * 5 )
*
* - icon    ( string,  optional )
*
* - action  ( string,  optional )
* - callback( func,    optional )
*           ( when action != "" must set callback )
*
* Param:
* - string:
*   - 1:content
*   - 2:type content or title content
*
* - object
*   - { type: xxx, title: xxx, content: xxx, mode: xxx, icon: xxx, delay: 500, action: xxx, callback:()=>{xxxx} }
*
* Example:
* new Notify().Render( "一个参数的 toast" );
* new Notify().Render( 0, "两个参数的 toast" );
* new Notify().Render( 1, "两个参数的 toast" );
* new Notify().Render( 2, "两个参数的 toast" );
* new Notify().Render( 3, "两个参数的 toast" );
* new Notify().Render( "snackbar", "两个参数的 snackbar" );
* new Notify().Render( "三个参数的 callback", "undo", ()=>{console.log("bbbbbb")} );
* new Notify().Render( "snackbar", "四个参数的 snackbar callback", "undo", ()=>{console.log("rrrrrr")} );
* new Notify().Render( "SimpTab 版本提示", `已更新到最新版本,详细请看 <a>CHANGELOG</a>` );
* new Notify().Render({ content: "带 icon 的 toast", icon: "<path>/weight_icon.png" } );
* new Notify().Render({ content: "带 delay 的 toast", delay: 10000 } );
* new Notify().Render({ content: "带 icon 的 snackbar", icon: "<path>/fontsize_icon.png" });
* new Notify().Render({ content: "带 callback 的 toast", icon: "<path>/icon.png", mode: "snackbar", action: "提交", callback: ()=>{console.log("dddddddd")}} );
* new Notify().Render( "错误的 callback", "undo", '()=>{console.log("eeeeeeee")}' );
* new Notify().Render({ content: "带确认的 toast", action: "提交", cancel: "取消", callback: type => {
     console.log( "current type is", type )
  }});
  new Notify().Render({ content: "一直存在带 close 的 toast", state: "holdon" });
*
  const notify = new Notify().Render({ content: "加载中,请稍等...", state: "loading" });
  setTimeout( ()=>{
    notify.complete();
    new Notify().Render("加载完成!");
  }, 2000);
* Notify.Position = rt( default ) | rb | lt | lb
*
*/
var Notify = ( function () {
    var VERSION = "2.0.1",
        name    = "notify",
        root    = "notify-gp",
        roottmpl= "<" + root + ">",
        num     = 0,
        NORMAL  = 0,
        SUCCESS = 1,
        WARNING = 2,
        ERROR   = 3,
        MODE    = {
            toast    : "toast",
            modal    : "modal",
            snackbar : "snackbar",
        },
        STATE   = {
            loading  : "loading",
            holdon   : "holdon",
        },
        POSITION= {
            lefttop     : "lt",
            leftbottom  : "lb",
            rightbottom : "rb",
        },
        options = {
            version : VERSION,
            title   : "",
            content : "",
            type    : NORMAL,
            mode    : MODE.toast,
            state   : undefined,
            flat    : false,
            delay   : 1000 * 5,
            icon    : "",
            action  : "",
            cancel  : "",
            callback: undefined,
            complete: undefined,
        },
        timer      = {},
        $root,
        TMPL       = '\
        <notify>\
            <notify-a href="javascript:;"><notify-span></notify-span></notify-a>\
            <notify-i></notify-i>\
            <notify-title></notify-title>\
            <notify-content></notify-content>\
            <notify-action></notify-action>\
            <notify-cancel></notify-cancel>\
        </notify>',
        loading    = '\
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="lds-rolling">\
                <circle stroke="#fff" stroke-width="10" cx="50" cy="50" fill="none" ng-attr-stroke="{{config.color}}" ng-attr-stroke-width="{{config.width}}" ng-attr-r="{{config.radius}}" ng-attr-stroke-dasharray="{{config.dasharray}}" r="30" stroke-dasharray="141.37166941154067 49.12388980384689" transform="rotate(102 50 50)">\
                    <animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animateTransform>\
                </circle>\
            </svg>',
        prefix     = function( value ) {
            return name + "-" + value;
        },
        registyElement = function( name, elements ) {
            elements.forEach( function( item ) {
                document.createElement( prefix( item ));
            });
        },
        closeHandle = function( event ) {
            $root.off( "click", "." + event.data + " notify-a", closeHandle );
            hidden( $(this).parent() );
        },
        delayHandler = function( item ) {
            clearTimeout( timer[item] );
            delete timer[item];
            hidden( this );
        },
        callbackHander = function( event ) {
            event.data[1] && event.data[1]( event.data[2] );
            $root.off( "click", "." + event.data[0] + " notify-action", callbackHander );
            hidden( $(this).parent() );
        },
        completeHandler = function() {
            hidden( this );
        },
        hidden = function( target ) {
            target.addClass( "notify-hide" ).slideUp( 500, function() {
                target.remove();
                if ($root.children().length === 0 ) $root.css( "z-index", 0 );
            });
        },
        render = function() {
            var $target  = $( TMPL ),
                $title   = $target.find(prefix( "title"   )),
                $content = $target.find(prefix( "content" )),
                $close   = $target.find(prefix( "a"       )),
                $icon    = $target.find(prefix( "i"       )),
                $action  = $target.find(prefix( "action"  )),
                $cancel  = $target.find(prefix( "cancel"  )),
                item     = "notify-item-" + num++,
                position = this.constructor.Position;

            this.title   ? $title.text( this.title )     : $title.hide();
            this.content ? $content.html( this.content ) : $content.hide();

            if ( this.mode === MODE.modal ) {
                $target.addClass( "notify-modal" );
                $content.addClass( "notify-modal-content" );
                $root.on( "click", "." + item + " notify-a", item, closeHandle );
            } else {
                $close.hide();
                this.mode == MODE.snackbar && $target.addClass( "notify-snackbar" );
            }

            this.mode !== MODE.modal && this.icon !== "" &&
                $icon.css({ "background-image": "url(" + this.icon + ")", "display": "block" });

            switch( this.type ) {
                case 1:
                    $content.addClass( "notify-success" );
                    break;
                case 2:
                    $content.addClass( "notify-warning" );
                    break;
                case 3:
                    $content.addClass( "notify-error" );
                    break;
            }

            if ( this.action !== "" && this.callback && typeof this.callback == "function" ) {
                $content.css( "width", "100%" );
                $action.text( this.action ).css( "display", "block" );
                $root.on( "click", "." + item + " notify-action", [ item, this.callback, "action" ], callbackHander );
            }

            if ( this.cancel !== "" && this.callback && typeof this.callback == "function" ) {
                $content.css( "width", "100%" );
                $cancel.text( this.cancel ).css( "display", "block" );
                $root.on( "click", "." + item + " notify-cancel", [ item, this.callback, "cancel" ], callbackHander );
            }

            this.mode !== MODE.modal && this.state !== STATE.loading && this.state !== STATE.holdon && ( this.action == "" || !this.callback || typeof this.callback != "function" ) &&
                ( timer[item] = setTimeout( delayHandler.bind( $target, item ), this.delay ) );

            if ( this.state == STATE.loading ) {
                $icon.html( loading );
                $icon.css({ display: "block" });
                this.complete = completeHandler.bind( $target );
            }

            if ( this.state == STATE.holdon ) {
                $icon.css({ display: "block" }).addClass( "holdon" );
                $cancel.after( $icon[0].outerHTML );
                $target.find( "notify-i:first" ).remove();
                $root.on( "click", "." + item + " notify-i", [ item, this.callback, "holdon" ], callbackHander );
                if ( !this.action || !this.cancel ) $content.css({ width: "100%" });
            }

            if ( this.flat ) {
                $target.css({ "box-shadow": "none", "border-radius": "2px" });
            }

            if ( position == POSITION.rightbottom || position == POSITION.leftbottom ) {
                $target.css({ "transform-origin": "left bottom 0px" });
                $root.addClass( "notify-position-" + position + "-corner" );
            } else if ( position == POSITION.lefttop ) {
                $root.addClass( "notify-position-" + position + "-corner" );
            }

            $target.addClass( item );
            $root.append( $target ).css( "z-index", 2147483647 );
            this.mode == MODE.snackbar && $target.css( "margin-left", "-" + $target.width()/2 + "px" );
            setTimeout( function() { $target.addClass( "notify-show" ); }, 200 );
        };

    function Notify() {
        registyElement( name, [ "gp", "div", "a", "span", "title", "content", "i" ] );
        if ( $( "html" ).find ( root ).length == 0 ) {
            $( "html" ).append( roottmpl );
            $root = $( root );
        }
    }

    Notify.prototype.title   = options.title;
    Notify.prototype.content = options.content;
    Notify.prototype.type    = options.type;
    Notify.prototype.mode    = options.mode;
    Notify.prototype.state   = options.state;
    Notify.prototype.delay   = options.delay;
    Notify.prototype.icon    = options.icon;
    Notify.prototype.flat    = options.flat;
    Notify.prototype.action  = options.action;
    Notify.prototype.cancel  = options.cancel;
    Notify.prototype.callback= options.callback;
    Notify.prototype.complete= options.complete;
    Notify.Position          = undefined;

    Notify.prototype.Render  = function () {

        var self = this;

        if ( arguments.length === 1 && typeof arguments[0] === "object" ) {
            options = arguments[0];

            Object.keys( options ).forEach( function( item ) {
                self[item] = options[item];
            });

            render.bind( self )();
        }
        else if ( typeof arguments[0] !== "object" && arguments.length > 0 && arguments.length < 5 ) {
            switch ( arguments.length ) {
                case 1:
                    this.content = arguments[0];
                    break;
                case 2:
                    if ( arguments[0] == MODE.snackbar ) {
                        this.mode = arguments[0];
                    }
                    else if ( typeof arguments[0] == "number" ) {
                        this.type  = arguments[0];
                    } else {
                        this.mode  = MODE.modal,
                        this.title = arguments[0];
                    }
                    this.content   = arguments[1];
                    break;
                case 3:
                    this.content   = arguments[0];
                    this.action    = arguments[1];
                    this.callback  = arguments[2];
                    break;
                case 4:
                    if ( arguments[0] == MODE.snackbar ) {
                        this.mode      = arguments[0];
                        this.content   = arguments[1];
                        this.action    = arguments[2];
                        this.callback  = arguments[3];
                    }
                    break;
            }
            render.bind( self )();
        }
        else {
            console.error( "Arguments error", arguments );
        }
        return self;
    };

    Notify.prototype.Clone  = function () {
        return new Notify();
    };

    return Notify;

})();

module.exports = Notify;