├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .travis.yml ├── .yo-rc.json ├── LICENSE ├── README.md ├── bower.json ├── dist ├── vg-src.js └── vg-src.min.js ├── gulpfile.js ├── karma-dist-concatenated.conf.js ├── karma-dist-minified.conf.js ├── karma-src.conf.js ├── package.json ├── sample ├── index.html └── index.js ├── src ├── _end.js ├── _start.js ├── vgSrc.config.js ├── vgSrc.directive.js ├── vgSrc.ie.js └── vgSrc.js └── test └── unit └── vg-src └── vgSrcSpec.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower" 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .~lock.* 3 | .buildpath 4 | .DS_Store 5 | .idea 6 | .project 7 | .settings 8 | *.log 9 | 10 | # Ignore node stuff 11 | node_modules/ 12 | npm-debug.log 13 | libpeerconnection.log 14 | 15 | # OS-specific 16 | .DS_Store 17 | 18 | # Bower components 19 | bower 20 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": false, 43 | "moz": false, 44 | "multistr": false, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false, 59 | "$": false 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: ["0.10"] 3 | before_script: 4 | - npm install -g bower 5 | - bower install 6 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-angularjs-library": { 3 | "props": { 4 | "author": { 5 | "name": "van", 6 | "email": "1321907687@qq.com" 7 | }, 8 | "libraryName": { 9 | "original": "vgSrc", 10 | "camelized": "vgSrc", 11 | "dasherized": "vg-src", 12 | "slugified": "vgsrc", 13 | "parts": [ 14 | "vgsrc" 15 | ] 16 | }, 17 | "includeModuleDirectives": true, 18 | "includeModuleFilters": false, 19 | "includeModuleServices": false, 20 | "includeAngularModuleResource": false, 21 | "includeAngularModuleCookies": false, 22 | "includeAngularModuleSanitize": false, 23 | "librarySrcDirectory": "src/vg-src", 24 | "libraryUnitTestDirectory": "test/unit/vg-src", 25 | "libraryUnitE2eDirectory": "test/e2e/vg-src" 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 van 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vgSrc 2 | ## 简介 3 | 一个简单的 Angular 图片加载插件,插件根据图片资源的不同加载状态,显示不同图片。 4 | 5 | ## 使用 6 | 1. 推荐使用 bower 加载: 7 | ```bash 8 | bower install vgSrc --save 9 | ``` 10 | 并引入: 11 | ```html 12 | 13 | ``` 14 | 15 | 1. 也可下载源码,在页面引入: 16 | ```html 17 | } 18 | ``` 19 | 20 | ## example 21 | 1. 简单实例 22 | ```html 23 | 24 | ``` 25 | 26 | 1. 添加样式 27 | ```html 28 | 29 | ``` 30 | 31 | 1. 监听事件 32 | ```html 33 | 34 | ``` 35 | 36 | 更多实例,请查阅 **[sample/index.html](https://github.com/VanMess/vgSrc/blob/master/sample/index.html)** 文件 37 | 38 | ## API 39 | #### vgSrcConfigProvider 40 | 配置接口: 41 | ```javascript 42 | vgSrcConfigProvider.$set(config) 43 | ``` 44 | 45 | example: 46 | ```javascript 47 | ng.module('vgSrc.sample', ['vgSrc']).config([ 48 | 'vgSrcConfigProvider', 49 | function(vgSrcConfigProvider) { 50 | vgSrcConfigProvider.$set({ 51 | debug: false, 52 | error: 'http://ico.ooopic.com/iconset01/status-icons/gif/99589.gif', 53 | onBegin: function($e) { 54 | // console.log('start load:' + $e.src); 55 | }, 56 | onError: function($e) { 57 | // console.log('failure load:' + $e.src); 58 | }, 59 | onLoad: function($e) { 60 | // console.log('complete load:' + $e.src); 61 | } 62 | }); 63 | } 64 | ]); 65 | ``` 66 | 67 | #### vgSrc (directive) 68 | vgSrc 指令用法与 ngSrc 指令类型。指令支持 angular 表达式,如. 69 | ```html 70 | 71 | 72 | ``` 73 | 74 | ## 配置项 75 | #### 替换图片 76 | vgSrc 支持 loading、error、empty 状态下的图片替换: 77 | 78 | 1. vgSrc 指令求值结果为空时(null、undefined、空字符串),将显示 empty 值指定的图片 79 | 1. 开始加载时,将显示 loading 值指定的图片 80 | 1. 加载出错时,将显示 error 值指定的图片 81 | 1. 加载成功后,正常显示图片 82 | 83 | #### 事件 84 | vgSrc 支持 onBegin、onError、onLoad 事件,可通过 vgSrcConfigProvider 、 vgSrc 两种方式注册不同类型的事件处理器: 85 | 86 | 1. 通过 vgSrcConfigProvider 方式注册的监听器将做为默认的事件监听器,事件参数为:`$e{src:''}`,用法如: 87 | ```javascript 88 | onBegin:function($e){ 89 | console.log($e.src); 90 | } 91 | ``` 92 | 93 | 1. 通过 vgSrc 方式注册的监听器将覆盖默认的事件监听器,事件参数为:`$e{src:''}`,用法如: 94 | ```html 95 | 96 | ``` 97 | 98 | #### 样式class 99 | vgSrc 支持 loadingCls、loadedCls、errorCls、emptyCls 样式,可通过 vgSrcConfigProvider 、 vgSrc 两种方式注册 class 值: 100 | 101 | 1. 通过 vgSrcConfigProvider 方式注册的 class 将做为默认的 class ,用法如: 102 | ```javascript 103 | errorCls:'errorClass' 104 | ``` 105 | 106 | 1. 通过 vgSrc 方式注册的 class 将做为此image特定的 class,用法如: 107 | ```html 108 | 109 | ``` 110 | ** 注意,class 属性不支持angular表达式 —— 你只能传递简单的字符串 ** 111 | 112 | #### 配置项汇总 113 | ```javascript 114 | { 115 | // 启动调试模式 116 | debug: false, 117 | 118 | // 图片加载中的替换显示图片 119 | loading: '/loading.jpg', 120 | 121 | // 图片加载中的样式 class 122 | loadingCls: '', 123 | 124 | // 图片加载完成的样式 class 125 | loadedCls: '', 126 | 127 | // 图片加载失败的替换显示图片 128 | error: '/error.jpg', 129 | 130 | // 图片加载失败的样式 class 131 | errorCls: '', 132 | 133 | // 图片值为空时的替换显示图片 134 | empty: '', 135 | 136 | // 图片值为空时的样式 class 137 | emptyCls: '', 138 | 139 | // 资源开始加载事件 140 | 'onBegin': ng.noop, 141 | 142 | // 资源加载出错事件 143 | 'onError': ng.noop, 144 | 145 | // 资源加载完毕事件 146 | 'onLoad': ng.noop 147 | } 148 | ``` 149 | 150 | ## 兼容性 151 | 目前兼容主流浏览器及ie8 152 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vgSrc", 3 | "version": "0.1.0", 4 | "authors": [ 5 | { 6 | "name": "van", 7 | "email": "1321907687@qq.com" 8 | } 9 | ], 10 | "main": ["dist/vg-src.js"], 11 | "ignore": [ 12 | "src", 13 | "test", 14 | "gulpfile.js", 15 | "karma-*.conf.js", 16 | "**/.*", 17 | "sample" 18 | ], 19 | "dependencies": {}, 20 | "devDependencies": { 21 | "angular": ">=1.2.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dist/vg-src.js: -------------------------------------------------------------------------------- 1 | /* 2 | * angular-image-lazyload - v0.0.1 - 2015-10-14 3 | * https://github.com/VanMess/angular-image-lazyload 4 | * Copyright (c) 2014 Van (http://vanmess.github.io/) 5 | */ 6 | !(function(factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | // AMD 9 | define(['angular'], factory); 10 | } else { 11 | // Global Variables 12 | factory(window.angular); 13 | } 14 | })(function(ng) { 15 | 'use strict'; 16 | 17 | var DONT_ENUM = "propertyIsEnumerable,isPrototypeOf,hasOwnProperty,toLocaleString,toString,valueOf,constructor".split(","), 18 | hasOwn = ({}).hasOwnProperty; 19 | for (var i in { 20 | toString: 1 21 | }) { 22 | DONT_ENUM = false; 23 | } 24 | Object.keys = Object.keys || (function(obj) { //ecma262v5 15.2.3.14 25 | return function(obj) { 26 | var result = [], 27 | key; 28 | for (key in obj) { 29 | if (hasOwn.call(obj, key)) { 30 | result.push(key); 31 | } 32 | } 33 | if (DONT_ENUM && obj) { 34 | for (var i = 0; i < DONT_ENUM.length; i++) { 35 | key = DONT_ENUM[i++]; 36 | if (hasOwn.call(obj, key)) { 37 | result.push(key); 38 | } 39 | } 40 | } 41 | return result; 42 | }; 43 | })(); 44 | 45 | if (!Function.prototype.bind) { 46 | Function.prototype.bind = function(oThis) { 47 | if (typeof this !== "function") { 48 | // closest thing possible to the ECMAScript 5 internal IsCallable function 49 | throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 50 | } 51 | var aArgs = Array.prototype.slice.call(arguments, 1), 52 | fToBind = this, 53 | fNOP = function() {}, 54 | fBound = function() { 55 | return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, 56 | aArgs.concat(Array.prototype.slice.call(arguments))); 57 | }; 58 | fNOP.prototype = this.prototype; 59 | fBound.prototype = new fNOP(); 60 | return fBound; 61 | }; 62 | } 63 | 64 | // Create all modules and define dependencies to make sure they exist 65 | // and are loaded in the correct order to satisfy dependency injection 66 | // before all nested files are concatenated by Gulp 67 | 68 | angular.module('vgSrc', []); 69 | 70 | /* 71 | * The provider of this module, just for setting default config. 72 | */ 73 | var 74 | 75 | // default setting 76 | defaults = { 77 | debug: false, 78 | // place image content when it begin to load real image resource. 79 | loading: 'data:image/gif;base64,R0lGODlh3ACHAPf/AM/o/HW++Pj8/9bs/dLq/cLi/Duj9Mbk/N/w/b3g+/X6/u72/jag9Nvu/S2c9Mzm/L7g++r1/pzQ+kOm9bre+0eo9Uyq9VCs9oLE+JDK+bbc+3nA+ECl9ebz/jqi9KDS+kKm9Tih9K3Y+6zY+z+k9bLb+2a292C09jSf9Mjl/FSu9nK894nH+ajW+sTj/JPM+X7C+IbG+HS992q492K194vI+Viw9m2696bV+qrX+orI+WS290ao9V2y9uf0/bTc+7je+5fO+aLT+iiZ84DD+DKe9OLx/ZLM+bDa+4TF+KTU+my691av9l6z9i+d9Fqx9nC890qq9Wi49+Py/Z7R+nzB+JbO+cDh/OLy/ZrP+o7K+ev2/lGt9k+s9bne+7jd+5vQ+ePy/iqa83K8+Pj7/8Tk/Fuy9pjO+trt/XzC+CaZ85LL+Y3J+b/h+9br/UWn9Vaw9iyb9Ge391Ku9pzQ+Tmi9IXG+C2c89Lp/VCs9eDw/tHq/azX+lSu9VKt9Uyq9nd3fba2uoCAhpKSl/b29sDAwqSkqNLS1OTk5e3t7puboP3+/9nt/a2tsfP5/t3v/eHx/d7v/dvb3ImJjuf0/uXz/tTr/eTy/uz2/uDw/f7//8rm/P7+/9Xr/e/4/vL5/vD4/vv9//f7//b7/9Dp/On1/vH4/vr9/9zu/Xi/+Pb7/k6r9Ump9ZbN+fz+/9jt/cnJy////8Hi/NHp/e73/rvf+3C799zv/cvm/O32/vn8/zGe9Mzn/Pz9/8nm/On0/kGl9Wu597Pb+9fs/aPU+tHp/PH5/p/S+vf7/uDx/eXy/q/Z+/P6/l+09tPq/T2j9c3n/OHw/dDp/fb6/srl/Cyb82O19+Lx/jGd9NTr/On1/dXr/EGm9ebz/Z7R+W+79/T5/tTq/JnP+dXs/d/v/t3v/ni/93rA+Dqh9GCz90uq9Z/S+We496jV+rzf/FKu9U6r9uz1/uj1/vr8/vv8/+z3/tDo/NDo/dnu/ff8/6TT+mO291iv9oXF+H7B+P///yH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1NUE3MjNERDI5RkExMUU1QjcyQkJBODIwMkYzNDk3NCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1NUE3MjNERTI5RkExMUU1QjcyQkJBODIwMkYzNDk3NCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjU1QTcyM0RCMjlGQTExRTVCNzJCQkE4MjAyRjM0OTc0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU1QTcyM0RDMjlGQTExRTVCNzJCQkE4MjAyRjM0OTc0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMy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', 80 | 81 | // element would applied this class when it is loading. 82 | loadingCls: '', 83 | 84 | // element would applied this class when it is load success. 85 | loadedCls: '', 86 | 87 | // place image content when image resource fail to load. 88 | error: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAACHCAYAAAB9Eze1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFRENGQkY4MjI5RkExMUU1QkI5MDk4MDJGNDM0OEYxNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFRENGQkY4MzI5RkExMUU1QkI5MDk4MDJGNDM0OEYxNCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkVEQ0ZCRjgwMjlGQTExRTVCQjkwOTgwMkY0MzQ4RjE0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkVEQ0ZCRjgxMjlGQTExRTVCQjkwOTgwMkY0MzQ4RjE0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+XsvVEAAACbdJREFUeNrsnVtsHFcZ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', 89 | 90 | // element would applied this class when it faild to load. 91 | errorCls: '', 92 | 93 | // place image content when element's "src" attribute is empty(null,undefine). 94 | empty: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAAYCAMAAAAGTsm6AAAAMFBMVEXy8vL6+vr+/v7+/v7+/v7v7+/+/v7+/v7+/v7+/v7+/v729vb+/v4AAADt7e3+/v673auIAAAADnRSTlPXrYhVZuwimTMRRMJ3AKjyf0QAAAH3SURBVHjaxdbZkqowGEXhzMM/ZL//2x6IEYh0Cd1addaFUhbJZyKKRv9TZ1iSHirpU6Gme3BB888h3kXwj8PLePZCc0F0lNn1Z0Irl3AQYVhZYnVYY/Zj+Nxze/Aa64ghYyRfrHieZ4Gz398qRV6KiNyL24AsS06e/RGuKqBKpJrWI31NIDo1Tsrt+foR9tfwLresBLcerYvplUu4oMlamGH6BWwXjREZIMGIruBq9jP/Co8pmLmsc9IC1ao6TXaCM0xfttUZnqO3MAkVgjwGaofXklDPQGgUaMA1Q0zW0kx9gQ0fK29hTUQCzuwqzA4TzslzxeJWtbszTPd/uTweNQ4C2eFiZc0hCoP7cQ6HqzpZwPoZbkj34RpZHmRlpAHveeT5+upwChlNpKFZKTsM6CU8Rxz6KvrGT59MRjjDDDRXlnNdQ6xHWLbSDZg4yxa7+UuOeoZTDrU22OUx+H2rCw7RHRiRt8A6KVbP8INxETJ9xgRDI3MPPk48wamBfoZJimqYr2rBtlv82YqrAesGU647nIHoyvxWI/yH8O62tMOCdvw6iQHsESag7vAHW+3buJ9LB0qE3eAe5XAcEZH1Cyv2jO52auSf9+OpMSID6RtwALiOLbdY4/DuH0jq1/gnWx3HgXTnnH2dE20M0F/DQvrlClU99Q/TJ4uko/HGBAAAAABJRU5ErkJggg==', 95 | 96 | // element would applied this class when src attribute is empty(null,undefine). 97 | emptyCls: '', 98 | 99 | // event occurs when it start to load something. 100 | 'onBegin': ng.noop, 101 | 102 | // event occurs when it fail load something. 103 | 'onError': ng.noop, 104 | 105 | // event occurs when it finish to load something. 106 | 'onLoad': ng.noop 107 | }, 108 | 109 | provider = function() { 110 | var moduleConfig = ng.copy(defaults), 111 | result = { 112 | $set: _setConfig, 113 | $get: function() { 114 | return moduleConfig; 115 | } 116 | }; 117 | 118 | return result; 119 | 120 | function _setConfig(cfg) { 121 | 122 | if (!ng.isDefined(cfg)) return; 123 | 124 | ng.forEach(Object.keys(moduleConfig), function(key) { 125 | if (cfg.hasOwnProperty(key) && key !== 'debug') { 126 | moduleConfig[key] = cfg[key] + ''; 127 | } 128 | }); 129 | 130 | // init debug model 131 | if (cfg.hasOwnProperty('debug')) { 132 | moduleConfig.debug = !!cfg.debug; 133 | } 134 | 135 | // init events 136 | var events = ['onBegin', 'onError', 'onLoad'], 137 | tmp; 138 | ng.forEach(events, function(e) { 139 | tmp = ng.isFunction(cfg[e]) ? cfg[e] : ng.noop; 140 | moduleConfig[e] = (function(_old) { 141 | return function($scope, $e) { 142 | _old($e); 143 | }; 144 | })(tmp); 145 | }); 146 | } 147 | }; 148 | 149 | angular.module('vgSrc').provider('vgSrcConfig', [provider]); 150 | 151 | /* 152 | * An angular directive for image loading status present. 153 | */ 154 | var directive = function($parse, defaults) { 155 | var status = ['loading', 'empty', 'error'], 156 | statusCls = ['loadingCls', 'emptyCls', 'errorCls', 'loadedCls'], 157 | events = ['onBegin', 'onError', 'onLoad'], 158 | // angular's directive define object. 159 | defineObj = { 160 | priority: 99, 161 | restrict: 'A', 162 | name: 'vgSrc', 163 | compile: function(element, attrs) { 164 | var attrName = attrs.$normalize(defineObj.name), 165 | srcParser = $parse(attrs[attrName]); 166 | 167 | return function _link($scope, element, attrs) { 168 | var opt = ng.copy(defaults), 169 | $log = opt.debug ? console.log.bind(console) : ng.noop; 170 | // parse everything in status lists. 171 | ng.forEach(status, function(att) { 172 | if (ng.isString(attrs[att])) { 173 | // parse element's setting attribute use ng's '$parse' 174 | // so that users can define the configuration by ng's 'expression'. 175 | opt[att] = $parse(attrs[att])($scope); 176 | } 177 | }); 178 | 179 | // simply copy everything in statusCls lists. 180 | ng.forEach(statusCls, function(att) { 181 | if (ng.isString(attrs[att])) { 182 | opt[att] = attrs[att]; 183 | } 184 | }); 185 | 186 | // parse event handlers 187 | // so that we can occu 188 | ng.forEach(events, function(att) { 189 | if (ng.isString(attrs[att])) { 190 | opt[att] = $parse(attrs[att]); 191 | } 192 | }); 193 | 194 | // watching vgSrc attribute 195 | // so that we could dynamicly fresh element's image when each time user change the value 196 | $scope.$watch(function() { 197 | return srcParser($scope); 198 | }, function _bindImg(newVal, oldVal) { 199 | var $e = { 200 | src: newVal 201 | }; 202 | if (ng.isString(newVal) && newVal.length > 0) { 203 | attrs.$set('src', opt.loading); 204 | _refreshCls(opt['loadingCls']); 205 | opt['onBegin'].call($scope, $scope, $e); 206 | $log('start loading resource:' + $e.src); 207 | 208 | _lazyLoad(newVal, function() { 209 | attrs.$set('src', newVal); 210 | _refreshCls(opt['loadedCls']); 211 | opt['onLoad'].call($scope, $scope, $e); 212 | $log('success load resource:' + $e.src); 213 | }, function() { 214 | attrs.$set('src', opt.error); 215 | _refreshCls(opt['errorCls']); 216 | opt['onError'].call($scope, $scope, $e); 217 | $log('failure load resource:' + $e.src); 218 | }) 219 | } else { 220 | attrs.$set('src', opt.empty); 221 | _refreshCls(opt['emptyCls']); 222 | opt['onError'].call($scope, $scope, $e); 223 | $log('current img is empty'); 224 | } 225 | }); 226 | 227 | // clear element's status class 228 | // and add the new class 229 | function _refreshCls(cls) { 230 | ng.forEach(statusCls, function(cls) { 231 | element.removeClass(opt[cls]); 232 | }); 233 | element.addClass(cls); 234 | } 235 | }; 236 | 237 | } 238 | }; 239 | 240 | return defineObj; 241 | }; 242 | 243 | angular.module('vgSrc').directive('vgSrc', ['$parse', 'vgSrcConfig', directive]); 244 | 245 | /* 246 | * load function to excute a shadow load 247 | */ 248 | function _lazyLoad(src, loadCallback, errorCallback) { 249 | var $imgDom = ng.element(new Image()); 250 | loadCallback = ng.isFunction(loadCallback) ? loadCallback : ng.noop; 251 | errorCallback = ng.isFunction(errorCallback) ? errorCallback : ng.noop; 252 | 253 | $imgDom.bind('error', errorCallback.bind(this)).bind('load', loadCallback.bind(this)).attr('src', src); 254 | } 255 | 256 | }); 257 | -------------------------------------------------------------------------------- /dist/vg-src.min.js: -------------------------------------------------------------------------------- 1 | !function(A){"function"==typeof define&&define.amd?define(["angular"],A):A(window.angular)}(function(A){"use strict";function C(C,E,Q){var I=A.element(new Image);E=A.isFunction(E)?E:A.noop,Q=A.isFunction(Q)?Q:A.noop,I.bind("error",Q.bind(this)).bind("load",E.bind(this)).attr("src",C)}var E="propertyIsEnumerable,isPrototypeOf,hasOwnProperty,toLocaleString,toString,valueOf,constructor".split(","),Q={}.hasOwnProperty;for(var I in{toString:1})E=!1;Object.keys=Object.keys||function(){return function(A){var C,I=[];for(C in A)Q.call(A,C)&&I.push(C);if(E&&A)for(var g=0;g0?(B.$set("src",M.loading),D(M.loadingCls),M.onBegin.call(w,w,Q),R("start loading resource:"+Q.src),C(E,function(){B.$set("src",E),D(M.loadedCls),M.onLoad.call(w,w,Q),R("success load resource:"+Q.src)},function(){B.$set("src",M.error),D(M.errorCls),M.onError.call(w,w,Q),R("failure load resource:"+Q.src)})):(B.$set("src",M.empty),D(M.emptyCls),M.onError.call(w,w,Q),R("current img is empty"))})}}};return w};angular.module("vgSrc").directive("vgSrc",["$parse","vgSrcConfig",w])}); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var karma = require('karma').server; 3 | var concat = require('gulp-concat'); 4 | var uglify = require('gulp-uglify'); 5 | var rename = require('gulp-rename'); 6 | var path = require('path'); 7 | var plumber = require('gulp-plumber'); 8 | var runSequence = require('run-sequence'); 9 | var jshint = require('gulp-jshint'); 10 | 11 | /** 12 | * File patterns 13 | **/ 14 | 15 | // Root directory 16 | var rootDirectory = path.resolve('./'); 17 | 18 | // Source directory for build process 19 | var sourceDirectory = path.join(rootDirectory, './src'); 20 | 21 | var sourceFiles = [ 22 | 'vgSrc.ie.js', 23 | 'vgSrc.js', 24 | 'vgSrc.config.js', 25 | 'vgSrc.directive.js' 26 | ]; 27 | 28 | var lintFiles = [ 29 | 'gulpfile.js', 30 | // Karma configuration 31 | 'karma-*.conf.js' 32 | ].concat(sourceFiles); 33 | 34 | gulp.task('build', function() { 35 | var srcFiles = ['_start.js'].concat(sourceFiles); 36 | srcFiles.push('_end.js'); 37 | 38 | for (var i = 0; i < srcFiles.length; i++) { 39 | srcFiles[i] = path.join(sourceDirectory, srcFiles[i]); 40 | } 41 | gulp.src(srcFiles) 42 | .pipe(plumber()) 43 | .pipe(concat('vg-src.js')) 44 | .pipe(gulp.dest('./dist/')) 45 | .pipe(uglify()) 46 | .pipe(rename('vg-src.min.js')) 47 | .pipe(gulp.dest('./dist')); 48 | }); 49 | 50 | /** 51 | * Process 52 | */ 53 | gulp.task('process-all', function(done) { 54 | runSequence('jshint', 'test-src', 'build', done); 55 | }); 56 | 57 | /** 58 | * Watch task 59 | */ 60 | gulp.task('watch', function() { 61 | 62 | // Watch JavaScript files 63 | gulp.watch(sourceFiles, ['process-all']); 64 | }); 65 | 66 | /** 67 | * Validate source JavaScript 68 | */ 69 | gulp.task('jshint', function() { 70 | return gulp.src(lintFiles) 71 | .pipe(plumber()) 72 | .pipe(jshint()) 73 | .pipe(jshint.reporter('jshint-stylish')) 74 | .pipe(jshint.reporter('fail')); 75 | }); 76 | 77 | /** 78 | * Run test once and exit 79 | */ 80 | gulp.task('test-src', function(done) { 81 | karma.start({ 82 | configFile: __dirname + '/karma-src.conf.js', 83 | singleRun: true 84 | }, done); 85 | }); 86 | 87 | /** 88 | * Run test once and exit 89 | */ 90 | gulp.task('test-dist-concatenated', function(done) { 91 | karma.start({ 92 | configFile: __dirname + '/karma-dist-concatenated.conf.js', 93 | singleRun: true 94 | }, done); 95 | }); 96 | 97 | /** 98 | * Run test once and exit 99 | */ 100 | gulp.task('test-dist-minified', function(done) { 101 | karma.start({ 102 | configFile: __dirname + '/karma-dist-minified.conf.js', 103 | singleRun: true 104 | }, done); 105 | }); 106 | 107 | gulp.task('default', function() { 108 | runSequence('process-all', 'watch'); 109 | }); 110 | -------------------------------------------------------------------------------- /karma-dist-concatenated.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery' 23 | ], 24 | 25 | // list of files / patterns to load in the browser 26 | files: [ 27 | 'bower/angular/angular.js', 28 | 'bower/angular-mocks/angular-mocks.js', 29 | 'dist/vg-src.js', 30 | 'test/unit/**/*.js' 31 | ], 32 | 33 | 34 | // list of files to exclude 35 | exclude: [ 36 | ], 37 | 38 | 39 | // preprocess matching files before serving them to the browser 40 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 41 | preprocessors: { 42 | }, 43 | 44 | 45 | // test results reporter to use 46 | // possible values: 'dots', 'progress' 47 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 48 | reporters: ['progress'], 49 | 50 | 51 | // web server port 52 | port: 9876, 53 | 54 | 55 | // enable / disable colors in the output (reporters and logs) 56 | colors: true, 57 | 58 | 59 | // level of logging 60 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 61 | logLevel: config.LOG_INFO, 62 | 63 | 64 | // enable / disable watching file and executing tests whenever any file changes 65 | autoWatch: true, 66 | 67 | 68 | // start these browsers 69 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 70 | browsers: ['PhantomJS'], 71 | 72 | 73 | // Continuous Integration mode 74 | // if true, Karma captures browsers, runs the tests and exits 75 | singleRun: false 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /karma-dist-minified.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery' 23 | ], 24 | 25 | // list of files / patterns to load in the browser 26 | files: [ 27 | 'bower/angular/angular.js', 28 | 'bower/angular-mocks/angular-mocks.js', 29 | 'dist/vg-src.min.js', 30 | 'test/unit/**/*.js' 31 | ], 32 | 33 | 34 | // list of files to exclude 35 | exclude: [ 36 | ], 37 | 38 | 39 | // preprocess matching files before serving them to the browser 40 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 41 | preprocessors: { 42 | }, 43 | 44 | 45 | // test results reporter to use 46 | // possible values: 'dots', 'progress' 47 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 48 | reporters: ['progress'], 49 | 50 | 51 | // web server port 52 | port: 9876, 53 | 54 | 55 | // enable / disable colors in the output (reporters and logs) 56 | colors: true, 57 | 58 | 59 | // level of logging 60 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 61 | logLevel: config.LOG_INFO, 62 | 63 | 64 | // enable / disable watching file and executing tests whenever any file changes 65 | autoWatch: true, 66 | 67 | 68 | // start these browsers 69 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 70 | browsers: ['PhantomJS'], 71 | 72 | 73 | // Continuous Integration mode 74 | // if true, Karma captures browsers, runs the tests and exits 75 | singleRun: false 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /karma-src.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery', 23 | 'karma-spec-reporter' 24 | ], 25 | 26 | // list of files / patterns to load in the browser 27 | files: [ 28 | 'bower/angular/angular.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'src/**/*.module.js', 31 | 'src/**/*.js', 32 | 'test/unit/**/*.js' 33 | ], 34 | 35 | 36 | // list of files to exclude 37 | exclude: [ 38 | ], 39 | 40 | 41 | // preprocess matching files before serving them to the browser 42 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 43 | preprocessors: { 44 | }, 45 | 46 | 47 | // test results reporter to use 48 | // possible values: 'dots', 'progress' 49 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 50 | reporters: ['progress', 'spec'], 51 | 52 | 53 | // web server port 54 | port: 9876, 55 | 56 | 57 | // enable / disable colors in the output (reporters and logs) 58 | colors: true, 59 | 60 | 61 | // level of logging 62 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 63 | logLevel: config.LOG_INFO, 64 | 65 | 66 | // enable / disable watching file and executing tests whenever any file changes 67 | autoWatch: true, 68 | 69 | 70 | // start these browsers 71 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 72 | browsers: ['PhantomJS'], 73 | 74 | 75 | // Continuous Integration mode 76 | // if true, Karma captures browsers, runs the tests and exits 77 | singleRun: false 78 | }); 79 | }; 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vg-src", 3 | "version": "0.1.0", 4 | "author": { 5 | "name": "van", 6 | "email": "1321907687@qq.com" 7 | }, 8 | "description": "A simple angular plugin for load images, with placeholder during load ,error or empty.", 9 | "dependencies": {}, 10 | "repository": { 11 | "type": "git", 12 | "url": "git@github.com:VanMess/vgSrc.git" 13 | }, 14 | "devDependencies": { 15 | "chai": "^1.9.1", 16 | "chai-jquery": "^1.2.3", 17 | "gulp": "^3.8.7", 18 | "gulp-concat": "^2.3.4", 19 | "gulp-jshint": "^1.8.4", 20 | "gulp-plumber": "^0.6.6", 21 | "gulp-rename": "^1.2.0", 22 | "gulp-uglify": "^0.3.1", 23 | "jshint-stylish": "^0.4.0", 24 | "karma": "^0.12.22", 25 | "karma-chai": "^0.1.0", 26 | "karma-chai-jquery": "*", 27 | "karma-chrome-launcher": "^0.1.4", 28 | "karma-jasmine": "^0.1.5", 29 | "karma-jquery": "^0.1.0", 30 | "karma-mocha": "^0.1.8", 31 | "karma-phantomjs-launcher": "^0.1.4", 32 | "karma-sinon-chai": "^0.2.0", 33 | "karma-spec-reporter": "^0.0.18", 34 | "mocha": "^1.21.4", 35 | "run-sequence": "^1.0.2", 36 | "sinon": "^1.10.3", 37 | "sinon-chai": "^2.5.0" 38 | }, 39 | "engines": { 40 | "node": ">=0.8.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | vgSrc sample 10 | 38 | 39 | 40 | 41 |
42 |
43 |

error images

44 | 45 | 46 | 47 |
48 |
49 |

empty images

50 | 51 | 52 | 53 |
54 |
55 |

apply classes

56 | 57 | 58 |
59 |
60 |

loading status

61 | 62 | 63 | 64 |
65 |
66 |

events

67 | 68 |
69 |
70 |

in ng-repeat

71 |
    72 |
  • 73 | 74 |
  • 75 |
76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /sample/index.js: -------------------------------------------------------------------------------- 1 | !(function(ng, $root) { 2 | ng.module('vgSrc.sample', ['vgSrc']).config([ 3 | 'vgSrcConfigProvider', 4 | function(vgSrcConfigProvider) { 5 | vgSrcConfigProvider.$set({ 6 | debug: false, 7 | error: 'http://ico.ooopic.com/iconset01/status-icons/gif/99589.gif', 8 | onBegin: function($e) { 9 | // console.log('start load:' + $e.src); 10 | }, 11 | onError: function($e) { 12 | // console.log('failure load:' + $e.src); 13 | }, 14 | onLoad: function($e) { 15 | // console.log('complete load:' + $e.src); 16 | } 17 | }); 18 | } 19 | ]).controller('IndexController', [ 20 | '$scope', 21 | function($scope) { 22 | this.errorImg = 'http://ico.ooopic.com/iconset01/status-icons/gif/99589.gif'; 23 | this.emptyImg = 'http://ico.ooopic.com/iconset01/status-icons/gif/99474.gif'; 24 | this.loadingImg = 'http://ico.ooopic.com/iconset01/status-icons/gif/99494.gif'; 25 | 26 | this.currentImg = 'http://attach.bbs.miui.com/forum/201402/21/115847dwxfcspf4c54esin.jpg.thumb.jpg'; 27 | 28 | this.imgList = [ 29 | 'http://attach.bbs.miui.com/forum/201402/21/115847dwxfcspf4c54esin.jpg.thumb.jpg', 30 | 'http://attach.bbs.miui.com/forum/201402/21/115847dwxfcspf4c54esin.jpg.thumb.jpeg', 31 | 'http://pic2.52pk.com/files/150929/1283568_103401945.jpg' 32 | ]; 33 | this.switchImg = function() {}; 34 | this.log = function(content) { 35 | console.log(content); 36 | }; 37 | this.debug = function(content) { 38 | debugger; 39 | console.log(content); 40 | }; 41 | } 42 | ]); 43 | 44 | ng.bootstrap($root, ['vgSrc.sample']); 45 | })(window.angular, window.document); 46 | -------------------------------------------------------------------------------- /src/_end.js: -------------------------------------------------------------------------------- 1 | }); 2 | -------------------------------------------------------------------------------- /src/_start.js: -------------------------------------------------------------------------------- 1 | /* 2 | * angular-image-lazyload - v0.0.1 - 2015-10-14 3 | * https://github.com/VanMess/angular-image-lazyload 4 | * Copyright (c) 2014 Van (http://vanmess.github.io/) 5 | */ 6 | !(function(factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | // AMD 9 | define(['angular'], factory); 10 | } else { 11 | // Global Variables 12 | factory(window.angular); 13 | } 14 | })(function(ng) { 15 | 'use strict'; 16 | -------------------------------------------------------------------------------- /src/vgSrc.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The provider of this module, just for setting default config. 3 | */ 4 | var 5 | 6 | // default setting 7 | defaults = { 8 | debug: false, 9 | // place image content when it begin to load real image resource. 10 | loading: 'data:image/gif;base64,R0lGODlh3ACHAPf/AM/o/HW++Pj8/9bs/dLq/cLi/Duj9Mbk/N/w/b3g+/X6/u72/jag9Nvu/S2c9Mzm/L7g++r1/pzQ+kOm9bre+0eo9Uyq9VCs9oLE+JDK+bbc+3nA+ECl9ebz/jqi9KDS+kKm9Tih9K3Y+6zY+z+k9bLb+2a292C09jSf9Mjl/FSu9nK894nH+ajW+sTj/JPM+X7C+IbG+HS992q492K194vI+Viw9m2696bV+qrX+orI+WS290ao9V2y9uf0/bTc+7je+5fO+aLT+iiZ84DD+DKe9OLx/ZLM+bDa+4TF+KTU+my691av9l6z9i+d9Fqx9nC890qq9Wi49+Py/Z7R+nzB+JbO+cDh/OLy/ZrP+o7K+ev2/lGt9k+s9bne+7jd+5vQ+ePy/iqa83K8+Pj7/8Tk/Fuy9pjO+trt/XzC+CaZ85LL+Y3J+b/h+9br/UWn9Vaw9iyb9Ge391Ku9pzQ+Tmi9IXG+C2c89Lp/VCs9eDw/tHq/azX+lSu9VKt9Uyq9nd3fba2uoCAhpKSl/b29sDAwqSkqNLS1OTk5e3t7puboP3+/9nt/a2tsfP5/t3v/eHx/d7v/dvb3ImJjuf0/uXz/tTr/eTy/uz2/uDw/f7//8rm/P7+/9Xr/e/4/vL5/vD4/vv9//f7//b7/9Dp/On1/vH4/vr9/9zu/Xi/+Pb7/k6r9Ump9ZbN+fz+/9jt/cnJy////8Hi/NHp/e73/rvf+3C799zv/cvm/O32/vn8/zGe9Mzn/Pz9/8nm/On0/kGl9Wu597Pb+9fs/aPU+tHp/PH5/p/S+vf7/uDx/eXy/q/Z+/P6/l+09tPq/T2j9c3n/OHw/dDp/fb6/srl/Cyb82O19+Lx/jGd9NTr/On1/dXr/EGm9ebz/Z7R+W+79/T5/tTq/JnP+dXs/d/v/t3v/ni/93rA+Dqh9GCz90uq9Z/S+We496jV+rzf/FKu9U6r9uz1/uj1/vr8/vv8/+z3/tDo/NDo/dnu/ff8/6TT+mO291iv9oXF+H7B+P///yH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1NUE3MjNERDI5RkExMUU1QjcyQkJBODIwMkYzNDk3NCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1NUE3MjNERTI5RkExMUU1QjcyQkJBODIwMkYzNDk3NCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjU1QTcyM0RCMjlGQTExRTVCNzJCQkE4MjAyRjM0OTc0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU1QTcyM0RDMjlGQTExRTVCNzJCQkE4MjAyRjM0OTc0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMy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', 11 | 12 | // element would applied this class when it is loading. 13 | loadingCls: '', 14 | 15 | // element would applied this class when it is load success. 16 | loadedCls: '', 17 | 18 | // place image content when image resource fail to load. 19 | error: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAACHCAYAAAB9Eze1AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFRENGQkY4MjI5RkExMUU1QkI5MDk4MDJGNDM0OEYxNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFRENGQkY4MzI5RkExMUU1QkI5MDk4MDJGNDM0OEYxNCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkVEQ0ZCRjgwMjlGQTExRTVCQjkwOTgwMkY0MzQ4RjE0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkVEQ0ZCRjgxMjlGQTExRTVCQjkwOTgwMkY0MzQ4RjE0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+XsvVEAAACbdJREFUeNrsnVtsHFcZ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', 20 | 21 | // element would applied this class when it faild to load. 22 | errorCls: '', 23 | 24 | // place image content when element's "src" attribute is empty(null,undefine). 25 | empty: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAAYCAMAAAAGTsm6AAAAMFBMVEXy8vL6+vr+/v7+/v7+/v7v7+/+/v7+/v7+/v7+/v7+/v729vb+/v4AAADt7e3+/v673auIAAAADnRSTlPXrYhVZuwimTMRRMJ3AKjyf0QAAAH3SURBVHjaxdbZkqowGEXhzMM/ZL//2x6IEYh0Cd1addaFUhbJZyKKRv9TZ1iSHirpU6Gme3BB888h3kXwj8PLePZCc0F0lNn1Z0Irl3AQYVhZYnVYY/Zj+Nxze/Aa64ghYyRfrHieZ4Gz398qRV6KiNyL24AsS06e/RGuKqBKpJrWI31NIDo1Tsrt+foR9tfwLresBLcerYvplUu4oMlamGH6BWwXjREZIMGIruBq9jP/Co8pmLmsc9IC1ao6TXaCM0xfttUZnqO3MAkVgjwGaofXklDPQGgUaMA1Q0zW0kx9gQ0fK29hTUQCzuwqzA4TzslzxeJWtbszTPd/uTweNQ4C2eFiZc0hCoP7cQ6HqzpZwPoZbkj34RpZHmRlpAHveeT5+upwChlNpKFZKTsM6CU8Rxz6KvrGT59MRjjDDDRXlnNdQ6xHWLbSDZg4yxa7+UuOeoZTDrU22OUx+H2rCw7RHRiRt8A6KVbP8INxETJ9xgRDI3MPPk48wamBfoZJimqYr2rBtlv82YqrAesGU647nIHoyvxWI/yH8O62tMOCdvw6iQHsESag7vAHW+3buJ9LB0qE3eAe5XAcEZH1Cyv2jO52auSf9+OpMSID6RtwALiOLbdY4/DuH0jq1/gnWx3HgXTnnH2dE20M0F/DQvrlClU99Q/TJ4uko/HGBAAAAABJRU5ErkJggg==', 26 | 27 | // element would applied this class when src attribute is empty(null,undefine). 28 | emptyCls: '', 29 | 30 | // event occurs when it start to load something. 31 | 'onBegin': ng.noop, 32 | 33 | // event occurs when it fail load something. 34 | 'onError': ng.noop, 35 | 36 | // event occurs when it finish to load something. 37 | 'onLoad': ng.noop 38 | }, 39 | 40 | provider = function() { 41 | var moduleConfig = ng.copy(defaults), 42 | result = { 43 | $set: _setConfig, 44 | $get: function() { 45 | return moduleConfig; 46 | } 47 | }; 48 | 49 | return result; 50 | 51 | function _setConfig(cfg) { 52 | 53 | if (!ng.isDefined(cfg)) return; 54 | 55 | ng.forEach(Object.keys(moduleConfig), function(key) { 56 | if (cfg.hasOwnProperty(key) && key !== 'debug') { 57 | moduleConfig[key] = cfg[key] + ''; 58 | } 59 | }); 60 | 61 | // init debug model 62 | if (cfg.hasOwnProperty('debug')) { 63 | moduleConfig.debug = !!cfg.debug; 64 | } 65 | 66 | // init events 67 | var events = ['onBegin', 'onError', 'onLoad'], 68 | tmp; 69 | ng.forEach(events, function(e) { 70 | tmp = ng.isFunction(cfg[e]) ? cfg[e] : ng.noop; 71 | moduleConfig[e] = (function(_old) { 72 | return function($scope, $e) { 73 | _old($e); 74 | }; 75 | })(tmp); 76 | }); 77 | } 78 | }; 79 | 80 | angular.module('vgSrc').provider('vgSrcConfig', [provider]); 81 | -------------------------------------------------------------------------------- /src/vgSrc.directive.js: -------------------------------------------------------------------------------- 1 | /* 2 | * An angular directive for image loading status present. 3 | */ 4 | var directive = function($parse, defaults) { 5 | var status = ['loading', 'empty', 'error'], 6 | statusCls = ['loadingCls', 'emptyCls', 'errorCls', 'loadedCls'], 7 | events = ['onBegin', 'onError', 'onLoad'], 8 | // angular's directive define object. 9 | defineObj = { 10 | priority: 99, 11 | restrict: 'A', 12 | name: 'vgSrc', 13 | compile: function(element, attrs) { 14 | var attrName = attrs.$normalize(defineObj.name), 15 | srcParser = $parse(attrs[attrName]); 16 | 17 | return function _link($scope, element, attrs) { 18 | var opt = ng.copy(defaults), 19 | $log = opt.debug ? console.log.bind(console) : ng.noop; 20 | // parse everything in status lists. 21 | ng.forEach(status, function(att) { 22 | if (ng.isString(attrs[att])) { 23 | // parse element's setting attribute use ng's '$parse' 24 | // so that users can define the configuration by ng's 'expression'. 25 | opt[att] = $parse(attrs[att])($scope); 26 | } 27 | }); 28 | 29 | // simply copy everything in statusCls lists. 30 | ng.forEach(statusCls, function(att) { 31 | if (ng.isString(attrs[att])) { 32 | opt[att] = attrs[att]; 33 | } 34 | }); 35 | 36 | // parse event handlers 37 | // so that we can occu 38 | ng.forEach(events, function(att) { 39 | if (ng.isString(attrs[att])) { 40 | opt[att] = $parse(attrs[att]); 41 | } 42 | }); 43 | 44 | // watching vgSrc attribute 45 | // so that we could dynamicly fresh element's image when each time user change the value 46 | $scope.$watch(function() { 47 | return srcParser($scope); 48 | }, function _bindImg(newVal, oldVal) { 49 | var $e = { 50 | src: newVal 51 | }; 52 | if (ng.isString(newVal) && newVal.length > 0) { 53 | attrs.$set('src', opt.loading); 54 | _refreshCls(opt['loadingCls']); 55 | opt['onBegin'].call($scope, $scope, $e); 56 | $log('start loading resource:' + $e.src); 57 | 58 | _lazyLoad(newVal, function() { 59 | attrs.$set('src', newVal); 60 | _refreshCls(opt['loadedCls']); 61 | opt['onLoad'].call($scope, $scope, $e); 62 | $log('success load resource:' + $e.src); 63 | }, function() { 64 | attrs.$set('src', opt.error); 65 | _refreshCls(opt['errorCls']); 66 | opt['onError'].call($scope, $scope, $e); 67 | $log('failure load resource:' + $e.src); 68 | }) 69 | } else { 70 | attrs.$set('src', opt.empty); 71 | _refreshCls(opt['emptyCls']); 72 | opt['onError'].call($scope, $scope, $e); 73 | $log('current img is empty'); 74 | } 75 | }); 76 | 77 | // clear element's status class 78 | // and add the new class 79 | function _refreshCls(cls) { 80 | ng.forEach(statusCls, function(cls) { 81 | element.removeClass(opt[cls]); 82 | }); 83 | element.addClass(cls); 84 | } 85 | }; 86 | 87 | } 88 | }; 89 | 90 | return defineObj; 91 | }; 92 | 93 | angular.module('vgSrc').directive('vgSrc', ['$parse', 'vgSrcConfig', directive]); 94 | 95 | /* 96 | * load function to excute a shadow load 97 | */ 98 | function _lazyLoad(src, loadCallback, errorCallback) { 99 | var $imgDom = ng.element(new Image()); 100 | loadCallback = ng.isFunction(loadCallback) ? loadCallback : ng.noop; 101 | errorCallback = ng.isFunction(errorCallback) ? errorCallback : ng.noop; 102 | 103 | $imgDom.bind('error', errorCallback.bind(this)).bind('load', loadCallback.bind(this)).attr('src', src); 104 | } 105 | -------------------------------------------------------------------------------- /src/vgSrc.ie.js: -------------------------------------------------------------------------------- 1 | var DONT_ENUM = "propertyIsEnumerable,isPrototypeOf,hasOwnProperty,toLocaleString,toString,valueOf,constructor".split(","), 2 | hasOwn = ({}).hasOwnProperty; 3 | for (var i in { 4 | toString: 1 5 | }) { 6 | DONT_ENUM = false; 7 | } 8 | Object.keys = Object.keys || (function(obj) { //ecma262v5 15.2.3.14 9 | return function(obj) { 10 | var result = [], 11 | key; 12 | for (key in obj) { 13 | if (hasOwn.call(obj, key)) { 14 | result.push(key); 15 | } 16 | } 17 | if (DONT_ENUM && obj) { 18 | for (var i = 0; i < DONT_ENUM.length; i++) { 19 | key = DONT_ENUM[i++]; 20 | if (hasOwn.call(obj, key)) { 21 | result.push(key); 22 | } 23 | } 24 | } 25 | return result; 26 | }; 27 | })(); 28 | 29 | if (!Function.prototype.bind) { 30 | Function.prototype.bind = function(oThis) { 31 | if (typeof this !== "function") { 32 | // closest thing possible to the ECMAScript 5 internal IsCallable function 33 | throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 34 | } 35 | var aArgs = Array.prototype.slice.call(arguments, 1), 36 | fToBind = this, 37 | fNOP = function() {}, 38 | fBound = function() { 39 | return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, 40 | aArgs.concat(Array.prototype.slice.call(arguments))); 41 | }; 42 | fNOP.prototype = this.prototype; 43 | fBound.prototype = new fNOP(); 44 | return fBound; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/vgSrc.js: -------------------------------------------------------------------------------- 1 | // Create all modules and define dependencies to make sure they exist 2 | // and are loaded in the correct order to satisfy dependency injection 3 | // before all nested files are concatenated by Gulp 4 | 5 | angular.module('vgSrc', []); 6 | -------------------------------------------------------------------------------- /test/unit/vg-src/vgSrcSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('', function() { 4 | 5 | var module; 6 | var dependencies; 7 | dependencies = []; 8 | 9 | var hasModule = function(module) { 10 | return dependencies.indexOf(module) >= 0; 11 | }; 12 | 13 | beforeEach(function() { 14 | 15 | // Get module 16 | module = angular.module('vgSrc'); 17 | dependencies = module.requires; 18 | }); 19 | 20 | it('should load config module', function() { 21 | expect(hasModule('vgSrc.config')).to.be.ok; 22 | }); 23 | 24 | 25 | 26 | 27 | it('should load directives module', function() { 28 | expect(hasModule('vgSrc.directives')).to.be.ok; 29 | }); 30 | 31 | 32 | 33 | 34 | }); --------------------------------------------------------------------------------