I_GRIN_I

Util.js

Jan 4th, 2017
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function UtilLibrary() {
  2.  
  3.     function debounce(func, wait, immediate) {
  4.         // 'private' variable for instance
  5.         // The returned function will be able to reference this due to closure.
  6.         // Each call to the returned function will share this common timer.
  7.         var timeout;
  8.  
  9.         // Calling debounce returns a new anonymous function
  10.         return function() {
  11.             // reference the context and args for the setTimeout function
  12.             var context = this,
  13.                 args = arguments;
  14.  
  15.             // Should the function be called now? If immediate is true
  16.             //   and not already in a timeout then the answer is: Yes
  17.             var callNow = immediate && !timeout;
  18.  
  19.             // This is the basic debounce behaviour where you can call this
  20.             //   function several times, but it will only execute once
  21.             //   [before or after imposing a delay].
  22.             //   Each time the returned function is called, the timer starts over.
  23.             $.CancelScheduled(timeout);
  24.  
  25.             // Set the new timeout
  26.             timeout = $.Schedule(wait, function() {
  27.  
  28.                 // Inside the timeout function, clear the timeout variable
  29.                 // which will let the next execution run when in 'immediate' mode
  30.                 timeout = null;
  31.  
  32.                 // Check if the function already ran with the immediate flag
  33.                 if (!immediate) {
  34.                     // Call the original function with apply
  35.                     // apply lets you define the 'this' object as well as the arguments
  36.                     //    (both captured before setTimeout)
  37.                     func.apply(context, args);
  38.                 }
  39.             });
  40.  
  41.             // Immediate mode and no wait timer? Execute the function..
  42.             if (callNow) func.apply(context, args);
  43.         };
  44.     };
  45.  
  46.     // Returns a function, that, when invoked, will only be triggered at most once
  47.     // during a given window of time. Normally, the throttled function will run
  48.     // as much as it can, without ever going more than once per `wait` duration;
  49.     // but if you'd like to disable the execution on the leading edge, pass
  50.     // `{leading: false}`. To disable execution on the trailing edge, ditto.
  51.     function throttle(func, wait, options) {
  52.         var context, args, result;
  53.         var timeout = null;
  54.         var previous = 0;
  55.         if (!options) options = {};
  56.         var later = function() {
  57.             previous = options.leading === false ? 0 : Date.now();
  58.             timeout = null;
  59.             result = func.apply(context, args);
  60.             if (!timeout) context = args = null;
  61.         };
  62.         return function() {
  63.             var now = Date.now();
  64.             if (!previous && options.leading === false) previous = now;
  65.             var remaining = wait - (now - previous);
  66.             context = this;
  67.             args = arguments;
  68.             if (remaining <= 0 || remaining > wait) {
  69.                 if (timeout) {
  70.                     $.CancelScheduled(timeout);
  71.                     timeout = null;
  72.                 }
  73.                 previous = now;
  74.                 result = func.apply(context, args);
  75.                 if (!timeout) context = args = null;
  76.             } else if (!timeout && options.trailing !== false) {
  77.                 timeout = $.Schedule(remaining, later);
  78.             }
  79.             return result;
  80.         };
  81.     };
  82.  
  83.     function inherits(childCtor, parentCtor) {
  84.         childCtor.prototype = Object.create(parentCtor.prototype);
  85.         childCtor.prototype.constructor = childCtor;
  86.         childCtor.prototype.__super__ = parentCtor.prototype;
  87.     };
  88.  
  89.     function extend() {
  90.         for (var i = 1; i < arguments.length; i++) {
  91.             for (var key in arguments[i]) {
  92.                 if (arguments[i].hasOwnProperty(key)) {
  93.                     arguments[0][key] = arguments[i][key];
  94.                 }
  95.             }
  96.         }
  97.         return arguments[0];
  98.     }
  99.  
  100.     function getRandomInt(min, max) {
  101.         return Math.floor(Math.random() * (max - min + 1)) + min;
  102.     }
  103.  
  104.     function applyStyle(panel, styles) {
  105.         for (var style in styles) {
  106.             panel.style[style] = styles[style];
  107.         }
  108.     }
  109.  
  110.     function Collection(items) {
  111.         this.items = items || [];
  112.     }
  113.     extend(Collection.prototype, {
  114.         get: function(i) {
  115.             return this.items[i];
  116.         },
  117.         set: function(i, v) {
  118.             this.items[i] = v;
  119.             return this;
  120.         },
  121.         length: function(v) {
  122.             if (v || v == 0) this.items.length = v;
  123.             return this.items.length;
  124.         },
  125.         isEmpty: function() {
  126.             return !this.items.length;
  127.         },
  128.         last: function() {
  129.             return this.items[this.items.length - 1];
  130.         },
  131.         first: function() {
  132.             return this.items[0];
  133.         },
  134.         remove: function(v) {
  135.             var i = this.items.indexOf(v);
  136.             if (i != -1) return this.splice(i, 1);
  137.         },
  138.         clear: function() {
  139.             return this.splice(0, this.items.length);
  140.         }
  141.     });
  142.     Object.getOwnPropertyNames(Array.prototype).forEach(function(prop) {
  143.         if (typeof(Array.prototype[prop]) == 'function') {
  144.             Collection.prototype[prop] = function() {
  145.                 var ret = Array.prototype[prop].apply(this.items, arguments);
  146.                 return Array.isArray(ret) ? new Collection(ret) : ret;
  147.             }
  148.         }
  149.     });
  150.  
  151.     function observable(initialValue) {
  152.         var _value = initialValue;
  153.         var _subscribers = [];
  154.         var _notifySubscribers = true;
  155.         var _oldValue;
  156.  
  157.         function fn(newValue) {
  158.             if (newValue === undefined) return _value;
  159.             _oldValue = _value;
  160.             _value = newValue;
  161.             if (_notifySubscribers) fn.fireSubscriptions();
  162.         }
  163.         fn.subscribe = function(callback) {
  164.             var sub = new subscription(callback);
  165.             _subscribers.push(sub);
  166.             return sub;
  167.         }
  168.         fn.unsubscribe = function(sub) {
  169.             _subscribers.splice(_subscribers.indexOf(sub), 1);
  170.         }
  171.         fn.unsubscribeAll = function() {
  172.             _subscribers.length = 0;
  173.         }
  174.         fn.notifySubscribers = function(newValue) {
  175.             _notifySubscribers = newValue;
  176.         }
  177.         fn.fireSubscriptions = function() {
  178.             _subscribers.forEach(function(sub) {
  179.                 sub.callback(_value, _oldValue);
  180.             });
  181.         }
  182.         return fn;
  183.     }
  184.  
  185.     function subscription(callback) {
  186.         this.callback = callback;
  187.     }
  188.  
  189.     function mixin(target, src) {
  190.         var source = (typeof src == 'function') ? src() : src;
  191.         for (var fn in source) {
  192.             if (source.hasOwnProperty(fn) && fn.name != 'init') {
  193.                 target.prototype[fn] = source[fn];
  194.             }
  195.         }
  196.  
  197.         if (typeof source.init == 'function') {
  198.             if (target.prototype._mixInits === undefined) {
  199.                 target.prototype._mixInits = [];
  200.             }
  201.             target.prototype._mixInits.push(source.init);
  202.         }
  203.     };
  204.  
  205.     function Mixable() {
  206.         var mixInits = Object.getPrototypeOf(this)._mixInits;
  207.         if (mixInits !== undefined) {
  208.             for (var i = 0; i < mixInits.length; i++) {
  209.                 mixInits[i].call(this);
  210.             }
  211.         }
  212.     };
  213.  
  214.     function MixableArray() {
  215.         var self = extend([], this);
  216.         Object.setPrototypeOf(self, Object.getPrototypeOf(this));
  217.         var mixInits = Object.getPrototypeOf(this)._mixInits;
  218.         if (mixInits !== undefined) {
  219.             for (var i = 0; i < mixInits.length; i++) {
  220.                 mixInits[i].call(self);
  221.             }
  222.         }
  223.         return self;
  224.     };
  225.     inherits(MixableArray, Array);
  226.  
  227.     function mixInPanelProps(props) {
  228.         return {
  229.             init: function() {
  230.                 this._props = props;
  231.                 if (props) this.addPanelProps(props);
  232.             },
  233.             addPanelProps: function(props) {
  234.                 for (var prop in props) {
  235.                     this.addPanelProp(prop, props[prop]);
  236.                 }
  237.             },
  238.             addPanelProp: function(prop, initialValue) {
  239.                 this[prop] = observable(initialValue);
  240.             },
  241.             bindPanelProps: function(props) {
  242.                 props = props || this._props;
  243.                 for (var prop in props) {
  244.                     this.bindPanelProp(prop);
  245.                 }
  246.             },
  247.             bindPanelProp: function(prop) {
  248.                 var self = this;
  249.                 switch (prop) {
  250.                     case 'draggable':
  251.                         this[prop].subscribe(function(newValue) {
  252.                             self.panel.SetDraggable(newValue);
  253.                         });
  254.                         break;
  255.                     case 'parentPanel':
  256.                         this[prop].subscribe(function(newValue) {
  257.                             self.panel.SetParent(newValue);
  258.                         });
  259.                         break;
  260.                     case 'cssClasses':
  261.                         this[prop].subscribe(function(newValue, oldValue) {
  262.                             oldValue.forEach(function(c) {
  263.                                 if (newValue.indexOf(c) == -1) {
  264.                                     self.panel.RemoveClass(c);
  265.                                 }
  266.                             });
  267.                             newValue.forEach(function(c) {
  268.                                 if (oldValue.indexOf(c) == -1) {
  269.                                     self.panel.AddClass(c);
  270.                                 }
  271.                             });
  272.                         });
  273.                         break;
  274.                     default:
  275.                         this[prop].subscribe(function(newValue) {
  276.                             self.panel[prop] = newValue;
  277.                         });
  278.                         break;
  279.                 }
  280.             },
  281.             unbindPanelProps: function(props) {
  282.                 for (var prop in props) {
  283.                     this.unbindPanelProp(prop);
  284.                 }
  285.             },
  286.             unbindPanelProp: function(prop) {
  287.                 this[prop].unsubscribeAll();
  288.             },
  289.             updateProps: function(_props) {
  290.                 for (var prop in _props) {
  291.                     if (props.hasOwnProperty(prop) && this.hasOwnProperty(prop)) {
  292.                         this[prop](_props[prop]);
  293.                     }
  294.                 }
  295.             }
  296.         }
  297.     }
  298.  
  299.     function mixInStyleProps(styles) {
  300.         return {
  301.             init: function() {
  302.                 this.style = {};
  303.                 if (styles) this.addStyles(styles);
  304.             },
  305.             addStyles: function(styles) {
  306.                 for (var style in styles) {
  307.                     this.addStyle(style, styles[style]);
  308.                 }
  309.             },
  310.             addStyle: function(style, initialValue) {
  311.                 this.style[style] = observable(initialValue);
  312.                 switch (style) {
  313.                     case "x":
  314.                     case "y":
  315.                     case "z":
  316.                     case "width":
  317.                     case "height":
  318.                         this.style[style].suffix = "px";
  319.                         break;
  320.                     default:
  321.                         this.style[style].suffix = "";
  322.                         break;
  323.                 }
  324.             },
  325.             bindStyles: function() {
  326.                 for (var prop in this.style) {
  327.                     this.bindStyleProp(prop);
  328.                 }
  329.             },
  330.             bindStyleProp: function(prop) {
  331.                 var self = this;
  332.                 this.style[prop].subscribe(function(newValue) {
  333.                     self.panel.style[prop] = newValue + self.style[prop].suffix;
  334.                 });
  335.             },
  336.             unbindStyles: function() {
  337.                 for (var prop in this.style) {
  338.                     this.unbindStyleProp(prop);
  339.                 }
  340.             },
  341.             unbindStyleProp: function(prop) {
  342.                 this.style[prop].unsubscribeAll();
  343.             },
  344.             updateStyles: function(styles) {
  345.                 for (var style in this.style) {
  346.                     if (styles.hasOwnProperty(style)) {
  347.                         this.style[style](styles[style]);
  348.                     }
  349.                 }
  350.             }
  351.         }
  352.     };
  353.  
  354.     var mixInEvents = {
  355.         init: function() {
  356.             this._handlers = {};
  357.         },
  358.         registerHandlers: function(events) {
  359.             for (var event in events) {
  360.                 this.registerHandler(event, events[event]);
  361.             }
  362.         },
  363.         registerHandler: function(event, handler) {
  364.             this._handlers[event].push(handler);
  365.         },
  366.         unregisterHandler: function(event, handler) {
  367.             if (handler == undefined) {
  368.                 this._handlers[event].length = 0;
  369.                 return;
  370.             }
  371.             var i = this._handlers[event].indexOf(handler);
  372.             if (i != -1) {
  373.                 this._handlers[event].splice(i, 1);
  374.             }
  375.         },
  376.         fireEvent: function(event) {
  377.             var self = this;
  378.             var args = new Array(arguments.length);
  379.             // loop because you shouldn't slice on arguments
  380.             for (var i = 1; i < args.length; ++i) {
  381.                 args[i - 1] = arguments[i];
  382.             }
  383.             args[args.length - 1] = self;
  384.             this._handlers[event].forEach(function(handler) {
  385.                 handler.apply(self, args);
  386.             });
  387.         }
  388.     }
  389.  
  390.     function mixInHandlers() {
  391.         var events = ['OnDblClick', 'OnContextMenu', 'OnFocus', 'OnBlur', 'OnTabForward',
  392.             'OnActivate', 'OnMouseOver', 'OnMouseOut', 'OnInputSubmit'
  393.         ];
  394.         var dragEvents = ['OnDragEnter', 'OnDragDrop', 'OnDragLeave', 'OnDragStart', 'OnDragEnd'];
  395.         var m = {
  396.             init: function() {
  397.                 var self = this;
  398.                 events.concat(dragEvents).forEach(function(event) {
  399.                     self._handlers[event] = [];
  400.                     if (self[event]) {
  401.                         self.registerHandler(event, self[event].bind(self));
  402.                     }
  403.                 });
  404.             },
  405.             bindHandlers: function() {
  406.                 events.concat(dragEvents).forEach(this.bindHandler, this);
  407.             },
  408.             bindHandler: function(event) {
  409.                 if (dragEvents.indexOf(event) == -1) {
  410.                     this.panel.SetPanelEvent(event.toLowerCase(), this.fireEvent.bind(this, event));
  411.                 } else {
  412.                     $.RegisterEventHandler(event.substring(2), this.panel, this.fireEvent.bind(this, event));
  413.                 }
  414.             },
  415.             unbindHandlers: function() {
  416.                 events.forEach(this.unbindHandler, this);
  417.             },
  418.             unbindHandler: function() {
  419.                 this.panel.ClearPanelEvent(event.toLowerCase());
  420.             }
  421.         }
  422.         return m;
  423.     };
  424.  
  425.     var mixInPanelBind = {
  426.         init: function() {
  427.             this.panel = null;
  428.             this.parent = null;
  429.             this.root = null;
  430.             this.children = [];
  431.         },
  432.         initPanel: function(options) {
  433.             this.panel = options.panel || $.CreatePanel(options.panelType || "Panel", options.parentPanel, options.id || "");
  434.             this.panel.container = this;
  435.             if (options.layoutfile) this.panel.BLoadLayout(options.layoutfile, false, false);
  436.             //if (options.cssClass) this.panel.AddClass(options.cssClass);
  437.             this.root = options.root || this;
  438.             if (options.children) this.createChildren(options);
  439.         },
  440.         bindPanel: function(options) {
  441.             if (!options.skipBindHandlers) this.bindHandlers();
  442.             if (!options.skipBindStyles) {
  443.                 this.bindStyles();
  444.                 this.updateStyles(options.style || {});
  445.             }
  446.             if (!options.skipPanelProps) {
  447.                 this.bindPanelProps();
  448.                 this.updateProps(options);
  449.             }
  450.             if (!options.skipRegisterEvents) {
  451.                 this.registerHandlers(options.events || {});
  452.             }
  453.         },
  454.         createChildren: function(options) {
  455.             var self = this;
  456.             options.children.forEach(function(childOptions) {
  457.                 var childCtor = childOptions.ctor || Panel; //Object.getPrototypeOf(self).constructor;
  458.                 childOptions.parentPanel = childOptions.parentPanel || self.panel;
  459.                 childOptions.root = self.root;
  460.                 var child = new childCtor(childOptions);
  461.                 /*if (childOptions.parentPanel && child.parentPanel() != childOptions.parentPanel) {
  462.                   child.parentPanel(childOptions.parentPanel);
  463.                 }
  464.                 else {
  465.                   child.parentPanel(self.panel);
  466.                 }*/
  467.                 self.children.push(child);
  468.                 child.parent = self;
  469.                 child.root = self.root;
  470.             });
  471.         },
  472.         appendChild: function(child) {
  473.             this.children.push(child);
  474.             child.panel.SetParent(this.panel);
  475.         },
  476.         setParent: function(parent) {
  477.             if (this.parent == parent) return;
  478.             if (this.parent) {
  479.                 this.parent.children.splice(this.parent.children.indexOf(this), 1);
  480.             }
  481.             this.parent = parent;
  482.             parent.appendChild(this);
  483.         }
  484.     }
  485.  
  486.     function _Panel(options) {
  487.         if (!options.skipInitPanel) {
  488.             this.initPanel(options);
  489.             if (!options.skipBindPanel) this.bindPanel(options);
  490.         }
  491.         if (options.init) options.init.call(this, options);
  492.     }
  493.  
  494.     function Panel(options) {
  495.         Mixable.call(this);
  496.         return _Panel.call(this, options);
  497.     }
  498.     inherits(Panel, Mixable);
  499.     mixin(Panel, mixInPanelBind);
  500.     mixin(Panel, mixInStyleProps({
  501.         x: 0,
  502.         y: 0,
  503.         z: 0,
  504.         zIndex: 0,
  505.         width: null,
  506.         height: null
  507.     }, true));
  508.     mixin(Panel, mixInPanelProps({
  509.         draggable: true,
  510.         droppable: true,
  511.         visible: true,
  512.         html: false,
  513.         text: "",
  514.         hittest: false,
  515.         parentPanel: null,
  516.         cssClasses: []
  517.     }, true));
  518.     mixin(Panel, mixInEvents);
  519.     mixin(Panel, mixInHandlers);
  520.  
  521.     function PanelCollection(options) {
  522.         var self = MixableArray.call(this);
  523.         Object.setPrototypeOf(self, Object.getPrototypeOf(this));
  524.         _Panel.call(self, options);
  525.         return self;
  526.     }
  527.     inherits(PanelCollection, MixableArray);
  528.     mixin(PanelCollection, mixInPanelBind);
  529.     mixin(PanelCollection, mixInStyleProps({
  530.         x: 0,
  531.         y: 0,
  532.         z: 0,
  533.         zIndex: 0,
  534.         width: null,
  535.         height: null
  536.     }, true));
  537.     mixin(PanelCollection, mixInPanelProps({
  538.         draggable: true,
  539.         droppable: true,
  540.         visible: true,
  541.         html: false,
  542.         text: "",
  543.         hittest: false,
  544.         parentPanel: null,
  545.         cssClasses: []
  546.     }, true));
  547.     mixin(PanelCollection, mixInEvents);
  548.     mixin(PanelCollection, mixInHandlers);
  549.  
  550.     return {
  551.         debounce: debounce,
  552.         throttle: throttle,
  553.         getRandomInt: getRandomInt,
  554.         applyStyle: applyStyle,
  555.         Collection: Collection,
  556.         observable: observable,
  557.         inherits: inherits,
  558.         extend: extend,
  559.         mixin: mixin,
  560.         Mixable: Mixable,
  561.         MixableArray: MixableArray,
  562.         mixInPanelProps: mixInPanelProps,
  563.         mixInStyleProps: mixInStyleProps,
  564.         mixInEvents: mixInEvents,
  565.         mixInHandlers: mixInHandlers,
  566.         mixInPanelBind: mixInPanelBind,
  567.         Panel: Panel,
  568.         PanelCollection: PanelCollection
  569.     };
  570. }
  571.  
  572. (function() {
  573.     GameUI.CustomUIConfig().UtilLibrary = new UtilLibrary();
  574.  
  575.     $.Msg("util/util.js");
  576.     /*var panel = $.CreatePanel( "Panel", $.GetContextPanel(), "idtest" );
  577.     $.Msg("util/main.js ", panel.__proto__);
  578.  
  579.  
  580.     for (var x in $) {
  581.       $.Msg("util/main.js ", x);
  582.     }*/
  583. })();
Add Comment
Please, Sign In to add comment