├── .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 | });
--------------------------------------------------------------------------------