Gowhich

Durban's Blog

一、网页的大小和浏览器窗口的大小

首先,要明确两个基本概念。

一张网页的全部面积,就是它的大小。通常情况下,网页的大小由内容和CSS样式表决定。

浏览器窗口的大小,则是指在浏览器窗口中看到的那部分网页面积,又叫做viewport(视口)。

很显然,如果网页的内容能够在浏览器窗口中全部显示(也就是不出现滚动条),那么网页的大小和浏览器窗口的大小是相等的。如果不能全部显示,则滚动浏览器窗口,可以显示出网页的各个部分。

二、获取网页的大小

网页上的每个元素,都有clientHeight和clientWidth属性。这两个属性指元素的内容部分再加上padding的所占据的视觉面积,不包括border和滚动条占用的空间。

因此,document元素的clientHeight和clientWidth属性,就代表了网页的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
function getViewport() {
if (document.compatMode == "BackCompat") {
return {
width: document.body.clientWidth,
height: document.body.clientHeight
}
} else {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
}
}
}

上面的getViewport函数就可以返回浏览器窗口的高和宽。使用的时候,有三个地方需要注意:

1)这个函数必须在页面加载完成后才能运行,否则document对象还没生成,浏览器会报错。

2)大多数情况下,都是document.documentElement.clientWidth返回正确值。但是,在IE6的quirks模式中,document.body.clientWidth返回正确的值,因此函数中加入了对文档模式的判断。

3)clientWidth和clientHeight都是只读属性,不能对它们赋值。

三、获取网页大小的另一种方法

网页上的每个元素还有scrollHeight和scrollWidth属性,指包含滚动条在内的该元素的视觉面积。

那么,document对象的scrollHeight和scrollWidth属性就是网页的大小,意思就是滚动条滚过的所有长度和宽度。

仿照getViewport()函数,可以写出getPagearea()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
function getPagearea() {
if (document.compatMode == "BackCompat") {
return {
width: document.body.scrollWidth,
height: document.body.scrollHeight
}
} else {
return {
width: document.documentElement.scrollWidth,
height: document.documentElement.scrollHeight
}
}
}

但是,这个函数有一个问题。如果网页内容能够在浏览器窗口中全部显示,不出现滚动条,那么网页的clientWidth和scrollWidth应该相 等。但是实际上,不同浏览器有不同的处理,这两个值未必相等。所以,我们需要取它们之中较大的那个值,因此要对getPagearea()函数进行改写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getPagearea() {
if (document.compatMode == "BackCompat") {
return {
width: Math.max(document.body.scrollWidth,
document.body.clientWidth),
height: Math.max(document.body.scrollHeight,
document.body.clientHeight)
}
} else {
return {
width: Math.max(document.documentElement.scrollWidth,
document.documentElement.clientWidth),
height: Math.max(document.documentElement.scrollHeight,
document.documentElement.clientHeight)
}
}
}

四、获取网页元素的绝对位置

网页元素的绝对位置,指该元素的左上角相对于整张网页左上角的坐标。这个绝对位置要通过计算才能得到。

首先,每个元素都有offsetTop和offsetLeft属性,表示该元素的左上角与父容器(offsetParent对象)左上角的距离。所以,只需要将这两个值进行累加,就可以得到该元素的绝对坐标。

下面两个函数可以用来获取绝对位置的横坐标和纵坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function getElementLeft(element) {
var actualLeft = element.offsetLeft;
var current = element.offsetParent;

while (current !== null) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}

return actualLeft;
}

function getElementTop(element) {
var actualTop = element.offsetTop;
var current = element.offsetParent;

while (current !== null) {
actualTop += current.offsetTop;
current = current.offsetParent;
}

return actualTop;
}

由于在表格和iframe中,offsetParent对象未必等于父容器,所以上面的函数对于表格和iframe中的元素不适用。

五、获取网页元素的相对位置

网页元素的相对位置,指该元素左上角相对于浏览器窗口左上角的坐标。

有了绝对位置以后,获得相对位置就很容易了,只要将绝对坐标减去页面的滚动条滚动的距离就可以了。滚动条滚动的垂直距离,是document对象的scrollTop属性;滚动条滚动的水平距离是document对象的scrollLeft属性。

对上一节中的两个函数进行相应的改写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function getElementViewLeft(element) {
var actualLeft = element.offsetLeft;
var current = element.offsetParent;

while (current !== null) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}

if (document.compatMode == "BackCompat") {
var elementScrollLeft = document.body.scrollLeft;
} else {
var elementScrollLeft = document.documentElement.scrollLeft;
}

return actualLeft - elementScrollLeft;
}

function getElementViewTop(element) {
var actualTop = element.offsetTop;
var current = element.offsetParent;

while (current !== null) {
actualTop += current.offsetTop;
current = current.offsetParent;
}

if (document.compatMode == "BackCompat") {
var elementScrollTop = document.body.scrollTop;
} else {
var elementScrollTop = document.documentElement.scrollTop;
}

return actualTop - elementScrollTop;
}

scrollTop和scrollLeft属性是可以赋值的,并且会立即自动滚动网页到相应位置,因此可以利用它们改变网页元素的相对位置。另外,element.scrollIntoView()方法也有类似作用,可以使网页元素出现在浏览器窗口的左上角。

六、获取元素位置的快速方法

除了上面的函数以外,还有一种快速方法,可以立刻获得网页元素的位置。

那就是使用getBoundingClientRect()方法。它返回一个对象,其中包含了left、right、top、bottom四个属性,分别对应了该元素的左上角和右下角相对于浏览器窗口(viewport)左上角的距离。

所以,网页元素的相对位置就是

1
2
var X= this.getBoundingClientRect().left;
var Y =this.getBoundingClientRect().top;

再加上滚动距离,就可以得到绝对位置

1
2
var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;
var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;

目前,IE、Firefox 3.0+、Opera 9.5+都支持该方法,而Firefox 2.x、Safari、Chrome、Konqueror不支持。

原文网址:http://www.ruanyifeng.com/blog/2009/09/find_element_s_position_using_javascript.html

我的配置,感觉很友好,很有好感,喜欢的拿去用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# don't put duplicate lines in the history. See bash(1) for more options
# ... or force ignoredups and ignorespace
HISTCONTROL=ignoredups:ignorespace

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
localhost_ip='xxx.xxx.xxx.xxx'
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@$localhost_ip\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
#PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@$localhost_ip\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@$localhost_ip:\w\$ '
#PS1='${debian_chroot:+($debian_chroot)}\u@$localhost_ip\h:\w\$ '
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'

alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi

# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
#if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
# . /etc/bash_completion
#fi

使用代码创建自己的navigationbar:

环境:

1
2
3
xcode:Version 4.6.1 (4H512)

simulater:iPhone6.1

直接上代码:

MasterViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//
// MasterViewController.h
// vlinkagePerson
//
// Created by david on 13-4-14.
// Copyright (c) 2013年 david. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface MasterViewController : UIViewController

//导航栏
@property (strong, nonatomic) UINavigationBar *navbar;
//导航栏集合
@property (strong, nonatomic) UINavigationItem *navItem;
//左边按钮
@property (strong, nonatomic) UIBarButtonItem *searchButton;
//右边按钮
@property (strong, nonatomic) UIBarButtonItem *attentionButton;

//自定义方法
//搜索操作
-(void) searchEvent;
-(void) attentionList;

@end
MasterViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

//
// MasterViewController.m
// vlinkagePerson
//
// Created by david on 13-4-14.
// Copyright (c) 2013年 david. All rights reserved.
//

#import "MasterViewController.h"

@interface MasterViewController ()

@end

@implementation MasterViewController

@synthesize navbar,navItem,searchButton,attentionButton;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}

- (void)viewDidLoad
{

[super viewDidLoad];
// Do any additional setup after loading the view from its nib.

//创建一个导航栏
self.navbar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];

//创建一个导航栏集合
self.navItem = [[UINavigationItem alloc] initWithTitle:@"艺人列表"];

//在这个集合Item中添加标题,按钮
//style:设置按钮的风格,一共有三种选择
//action:@selector:设置按钮的点击事件
//创建一个左边按钮
self.searchButton = [[UIBarButtonItem alloc] initWithTitle:@"搜索" style:UIBarButtonItemStylePlain target:self action:@selector(searchEvent)];

//创建一个右边按钮
self.attentionButton = [[UIBarButtonItem alloc] initWithTitle:@"我的关注" style:UIBarButtonItemStylePlain target:self action:@selector(attentionList)];

//把导航栏集合添加到导航栏中,设置动画关闭
[self.navbar pushNavigationItem:self.navItem animated:YES];

//把左右两个按钮添加到导航栏集合中去
[self.navItem setLeftBarButtonItem:self.searchButton];
[self.navItem setRightBarButtonItem:self.attentionButton];

//将标题栏中的内容全部添加到主视图当中
[self.view addSubview:self.navbar];

}

-(void) searchEvent{

}

-(void) attentionList{

}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

CGGeometry类定义几何元素的结构和操作几何元素的函数。

1、数据类型:

CGFloat: 浮点值的基本类型

CGPoint: 表示一个二维坐标系中的点

CGSize: 表示一个矩形的宽度和高度

CGRect: 表示一个矩形的位置和大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef float CGFloat;// 32-bit
typedef double CGFloat;// 64-bit
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGSize CGSize;
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;

注意:CGRect数据结构的高度和宽度可以是负数。例如,一个矩形的原点是[0.0,0.0]和大小是[10.0,10.0]。这个矩形完全等同原点是[10.0,10.0]和大小是[-10.0,-10.0]的矩形。

2、使用值来创建几何元素的方法

CGPointMake、CGRectMake、CGSizeMake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CGPoint CGPointMake (
CGFloat x,
CGFloat y
);

CGSize CGSizeMake (
CGFloat width,
CGFloat height
);

CGRect CGRectMake (
CGFloat x,
CGFloat y,
CGFloat width,
CGFloat height
);

CGFloat ten=10.0f;
CGPoint point = CGPointMake(0.0f, 0.0f);
CGSize size = CGSizeMake(10.0f, 10.0f);
CGRect rect = CGRectMake(point.x, point.y, size.width, size.height);
NSLog(@"ten: %f", ten);
NSLog(@"point: %@", NSStringFromCGPoint(point));
NSLog(@"size: %@", NSStringFromCGSize(size));
NSLog(@"rect: %@", NSStringFromCGRect(rect));

didFinishLaunchingWithOptions 方法:顾名思义。在app开始运行时会调用里面的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//返回的是带有状态栏的矩形
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

CGRect bound = [[UIScreen mainScreen]bounds]; //返回的是不带有状态栏的Rect
NSLog(@"boundwith:%f boundheight:%f",bound.size.width,bound.size.height);
NSLog(@"boundx:%f boundy:%f",bound.origin.x,bound.origin.y);
//2012-08-03 23:21:45.716 DinkMixer[599:c07] boundwith:320.000000 boundheight:480.000000
//2012-08-03 23:21:45.719 DinkMixer[599:c07] boundx:0.000000 boundy:0.000000

CGRect appBound = [[UIScreen mainScreen]applicationFrame]; //返回的是带有状态栏的Rect
NSLog(@"appBoundwith:%f boundheight:%f",appBound.size.width,appBound.size.height);
NSLog(@"appBoundx:%f boundy:%f",appBound.origin.x,appBound.origin.y);
//2012-08-03 23:21:45.720 DinkMixer[599:c07] appBoundwith:320.000000 boundheight:460.000000
//2012-08-03 23:21:45.720 DinkMixer[599:c07] appBoundx:0.000000 boundy:20.000000

//很明显状态栏占用了空间20像素

MasterViewController *masterViewController = [[[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil] autorelease];//根据nib文件的名称来创建一个视图控制器

self.navigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];//创建一个导航控制器,并指定该导航控制器的根视图控制器为上面建立的masterViewController

self.window.rootViewController = self.navigationController;//窗体(window)有一个根视图控制器——这个视图控制器负责配置当窗体显示时最先显示的视图。要让你的视图控制器的内容显示在窗体中,需要去设置窗体的根视图控制器为你的视图控制器。

[self.window makeKeyAndVisible];//这行代码会让包含了视图控制器视图的Window窗口显示在屏幕上。
return YES;
}

1. mount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
:~$ mount
/dev/sda1 on / type ext4 (rw,errors=remount-ro,user_xattr)
proc on /proc type proc (rw,noexec,nosuid,nodev)
none on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
none on /dev type devtmpfs (rw,mode=0755)
none on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
none on /dev/shm type tmpfs (rw,nosuid,nodev)
none on /var/run type tmpfs (rw,nosuid,mode=0755)
none on /var/lock type tmpfs (rw,noexec,nosuid,nodev)
none on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
none on /var/lib/ureadahead/debugfs type debugfs (rw,relatime)
none on /proc/fs/vmblock/mountPoint type vmblock (rw)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
gvfs-fuse-daemon on /home/kysnail/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=kysnail)
:~$

2. df

1
2
3
4
5
6
7
8
9
10
:~$ df -lhT
文件系统 类型 容量 已用 可用 已用% 挂载点
/dev/sda1 ext4 19G 11G 7.8G 57% /
none devtmpfs 498M 248K 497M 1% /dev
none tmpfs 502M 252K 501M 1% /dev/shm
none tmpfs 502M 96K 502M 1% /var/run
none tmpfs 502M 0 502M 0% /var/lock
none tmpfs 502M 0 502M 0% /lib/init/rw
none debugfs 19G 11G 7.8G 57% /var/lib/ureadahead/debugfs
:~$

3. fdisk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
:~$ sudo fdisk /dev/sda

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
switch off the mode (command 'c') and change display units to
sectors (command 'u').

Command (m for help): c
DOS Compatibility flag is not set

Command (m for help): u
Changing display/entry units to sectors

Command (m for help): p

Disk /dev/sda: 21.5 GB, 21474836480 bytes
heads, 63 sectors/track, 2610 cylinders, total 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00077544

Device Boot Start End Blocks Id System
/dev/sda1 * 2048 40105983 20051968 83 Linux
/dev/sda2 40108030 41940991 916481 5 Extended
/dev/sda5 40108032 41940991 916480 82 Linux swap / Solaris

Command (m for help): q

4. file

1
2
3
4
5
:~$ sudo file -s /dev/sda
/dev/sda: x86 boot sector; partition 1: ID=0x83, active, starthead 32, startsector 2048, 40103936 sectors; partition 2: ID=0x5, starthead 254, startsector 40108030, 1832962 sectors, code offset 0x63
kysnail@ubunkysnail:~$ sudo file -s /dev/sda1
/dev/sda1: Linux rev 1.0 ext4 filesystem data, UUID=4942da40-8a49-4bfd-9dc2-45c906d48413 (needs journal recovery) (extents) (large files) (huge files)
:~$

5. parted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
:~$ sudo parted
GNU Parted 2.2
使用 /dev/sda
欢迎使用 GNU Parted! 输入 'help'可获得命令列表.
(parted) p
Model: VMware, VMware Virtual S (scsi)
磁盘 /dev/sda: 21.5GB
Sector size (logical/physical): 512B/512B
分区表:msdos

数字 开始: End 大小 类型 文件系统 标志
1049kB 20.5GB 20.5GB primary ext4 启动
20.5GB 21.5GB 938MB extended
20.5GB 21.5GB 938MB logical linux-swap(v1)

(parted)

6. 查看 fstab

1
2
3
4
5
6
7
8
9
10
11
12
13
# /etc/fstab: static file system information.
#
# Use 'blkid -o value -s UUID' to print the universally unique identifier
# for a device; this may be used with UUID= as a more robust way to name
# devices that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc nodev,noexec,nosuid 0 0
# / was on /dev/sda1 during installation
UUID=4942da40-8a49-4bfd-9dc2-45c906d48413 / ext4 errors=remount-ro,user_xattr 0 1
# swap was on /dev/sda5 during installation
UUID=935fb95d-771f-448e-9d23-4820106e1783 none swap sw 0 0
/dev/fd0 /media/floppy0 auto rw,user,noauto,exec,utf8 0 0

我要在本机链接我本机上虚拟机的mysql,我使用mac下的workbench,就就是连接不上,报错信息为:“Can’t connect to MySQL server on ‘10.211.55.5’ (61)”,查了好多资料,有一种方法解决了我的问题:

第一步:查看是都3306端口开启
使用ufw(不会安装的,请与我联系),

1
sudo ufw status

或者直接使用命令

1
netstat -an | grep 3306

如果结果显示类似:

1
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN

从结果可以看出3306端口只是在IP 127.0.0.1上监听,所以拒绝了其他IP的访问。

第二步:修改配置文件
修改文件 /etc/mysql/my.cnf文件,打开文件,找到下面内容:

1
2
3
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 127.0.0.1

把上面这一行注释掉或者把127.0.0.1换成合适的IP,建议注释掉。
重新启动后,重新使用netstat检测:

1
2
~# netstat -an | grep 3306
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN

第三步:

使用创建的用户登录一下,成功。

在终端运行svn命令.如果没有安装,系统会提示安装

1.首先需要安装Subversion软件:

1
sudo apt-get install subversion

2.建立一个文件夹作为版本库的根目录

1
mkdir /var/svnroot/

这个目录本身不是版本库,只是拿来装版本库的目录

3.进入这个目录,创建版本库

1
2
cd /var/svnroot/
svnadmin create mysvn

以后如果有多个项目,可以继续在/var/svnroot/下面create新的版本库

4.配置vlink

1
2
cd /var/svnroot/vlink/conf/
ls

将会看到以下文件

1
authz passwd svnserve.conf

首先编辑 svnserve.conf

1
vim svnserve.conf

其中 anon-access 表示 匿名用户的权限,auth-access 表示经过认证的用户的权限。去掉前面的#注释,顶格写。一般说来像这样就可以了:

1
2
anon-access = none
auth-access = write

然后看到下面有 password-db 这个配置项。 这个是配置使用的密码文件。

1
password-db = passwd

为了以后多个版本库同时运行,建议改这个文件到 /var/svnroot/下面。比如: /var/svnroot/passed

1
password-db =/var/svnroot/passed

同理,authz-db这个也是,像这样:

1
/var/svnroot/authz

然后有个东西叫做realm,这个貌似是连接svn服务器的时候的提示句子。。不过设置成vlink的名字肯定没错。比如 vlink

1
realm = vlink

其他的不管。保存退出。

5.编辑 /var/svnroot/passwd
这个简单,像这样就可以了:

1
2
3
[users]
username=password
username=password

6.启动svnserve

1
sudo svnserve -d -r /var/svnroot/

-r 后面的参数是svnroot位置,而不是某个版本库的位置
要关闭svnserve可以直接用 kill 结束掉那个进程

7.Configure iptables
如果服务器上设置了iptables的话,你需要开启3690端口.

1
2
iptables -A INPUT -p tcp -i eth0 --dport 3690 -j ACCEPT
/sbin/iptables -A INPUT -p tcp -i eth0 --dport 3690 -j ACCEPT

查看ipatbles: iptables -L 如果出现下面一行表示设置成功了:

1
… ACCEPT tcp – anywhere anywhere tcp dpt:svn

8.测试 在本地 svn co svn://xxx.xxx.xxx.xxx/vlink –username xxx –password xxx
如果还有问题的我建议是将svnserve.conf文件中的有关authz注释掉,在测试。
我做的时候是有上面的问题,后来师兄注释掉后就好了,具体我也不明白什么原因
如何将想要的svn库中文件备份导出和导入呢(这里我没有测试过,大家可以测试一下,我们共同探讨)

9.将原来的Repository导出为一个文件dumpfile

1
svnadmin dump path/to/old-repo > dumpfile.svn

10.将dumpfile导入到新的Repository

1
svnadmin load path/to/new-repo < dumpfile.svn

11.本机svn的快速迁移方法:

1
svnadmin hotcopy old_rep_path new_rep_path

12.将原先服务器的配置文件备份后复制到新服务器中
/etc/httpd/conf.d/subversion.conf
还有repository目录下的authfile、auth.conf也需要备份后复制到新服务器中

13.linux下重新定位SVN URL方法:
如果更换了SVN服务器,就需要重新定位,指向新的SVN URL。
重新定位命令:svn switch --relocate 原svn地址 新svn地址
如何查看原svn地址?
查看原svn路径方法:svn info

第一种:NSKeyedArchiver(加密形式)

代码很简单就不多解释了直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//=================NSKeyedArchiver========================
NSString *saveStr1 = @ "我是" ;
NSString *saveStr2 = @ "数据" ;
NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
//----Save
//这一句是将路径和文件名合成文件完整路径
NSString *Path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = [Path stringByAppendingPathComponent:@ "saveDatatest" ];
[NSKeyedArchiver archiveRootObject:array toFile:filename];
//用于测试是否已经保存了数据
saveStr1 = @ "hhhhhhiiii" ;
saveStr2 =@ "mmmmmmiiii" ;
//----Load
array = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];
saveStr1 = [array objectAtIndex:0];
saveStr2 = [array objectAtIndex:1];
NSLog(@ "str:%@" ,saveStr1);
NSLog(@ "astr:%@" ,saveStr2);

第二种:NSUserDefaults

举个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//=================NSUserDefaults========================
NSString *saveStr1 = @ "我是" ;
NSString *saveStr2 = @ "数据" ;
NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
//Save
NSUserDefaults *saveDefaults = [NSUserDefaults standardUserDefaults];
[saveDefaults setObject:array forKey:@ "SaveKey" ];
//用于测试是否已经保存了数据
saveStr1 = @ "hhhhhhiiii" ;
saveStr2 =@ "mmmmmmiiii" ;
//---Load
array = [saveDefaults objectForKey:@ "SaveKey" ];
saveStr1 = [array objectAtIndex:0];
saveStr2 = [array objectAtIndex:1];
NSLog(@ "str:%@" ,saveStr1);
NSLog(@ "astr:%@" ,saveStr2);

第三种:Write写入方式

举个例子,也很简单的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//=================Write写入方式========================
NSString *saveStr1 = @ "我是" ;
NSString *saveStr2 = @ "数据" ;
NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
//----Save
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(@ "没找到" );
}
NSMutableArray *saveDataArray=nil;
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:@ "Savedatas.plist" ];
[[NSArray arrayWithObjects:array,nil] writeToFile:appFile atomically:NO];
//用于测试是否已经保存了数据
saveStr1 = @ "hhhhhhiiii" ;
saveStr2 =@ "mmmmmmiiii" ;
//----Load
if ([[NSFileManager defaultManager] fileExistsAtPath:appFile]){
saveDataArray = [NSMutableArray arrayWithContentsOfFile:appFile];
}else{
saveDataArray = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@ "Savedatas" ofType:@ "plist" ]];
}
NSArray *strArray = [saveDataArray objectAtIndex:0];
saveStr1 = [strArray objectAtIndex:0];
saveStr2 = [strArray objectAtIndex:1];
NSLog(@ "str:%@" ,saveStr1);
NSLog(@ "astr:%@" ,saveStr2);

第四种:SQLite3

在使用sqlite3之前 你需要将libsqlite3.dylib这个类库加入到你的项目中

1
2
3
4
5
6
7
8
9
- (NSString *)dataFilePath{

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; //首先得到应用程序沙盒中Document文件夹的路径
return [documentsDirectory stringByAppendingPathComponent:kFilename]//返回你指定文件的路径

打开数据库

1
2
3
4
5
sqlite3 *database;
if(sqlite3_open([filePath UTF8String], &database)) {
sqlite3_close(database);
NSAssert(0,@"Failed to open database");
}

创建数据库

1
2
3
4
5
6
char *errorMsg;
NSString *createSQL = @"CREATE TABLE IF NOT EXISTS FIELDS (ROW INTEGER PRIMARY KEY,FIELD_DATA TEXT);";
if (sqlite3_exec(database, [createSQL UTF8String], NULL, NULL, &errorMsg)!=SQLITE_OK) {
sqlite3_close(database);
NSAssert1(0,@"Error creating table:%s",errorMsg);
}

数据查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NSString *query = @"SELECT ROW, FIELD_DATA FROM FIELDS ORDER BY ROW";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)==SQLITE_OK) {
while (sqlite3_step(statement)==SQLITE_ROW) {
int row = sqlite3_column_int(statement, 0);
char *rowData = (char *)sqlite3_column_text(statement, 1);

//NSString *fieldName = [[NSString alloc] initWithFormat:@"field&d",row];
//NSString *fieldValue = [[NSString alloc] initWithUTF8String:rowData];

//UITextField *field = [self valueForKey:fieldName];
//field.text = fieldValue;
//[fieldName release];
//[fieldValue release];
}
sqlite3_finalize(statement);
}
sqlite3_close(database);

数据插入/更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
sqlite3 *database;
if (sqlite3_open([[self dataFilePath] UTF8String], &database)) {
sqlite3_close(database);
NSAssert(0,@"Failed to open database");
}

for (int i=1; i<=4; i++) {
NSString *fieldName = [[NSString alloc] initWithFormat:@"field%d",i];
UITextField *field = [self valueForKey:fieldName];
[fieldName release];

char *errorMsg;
char *update = "INSERT OR REPLACE INTO FIELDS (ROW,FIELD_DATA) VALUES(?,?);"; //这里插入的值可以用nsstring替换,但是最好的做法是使用绑定,如果遇到特殊字符 这是不二选择

sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(database, update, -1, &stmt, nil)==SQLITE_OK) {
sqlite3_bind_int(stmt, 1, i);
sqlite3_bind_text(stmt, 2, [[field text] UTF8String], -1, NULL);
}
if (sqlite3_step(stmt)!=SQLITE_DONE) {
NSAssert(0,@"Error updating table:%s",errorMsg);
}
sqlite3_finalize(stmt);
}
sqlite3_close(database);

#######################可爱分割线#############################

对Write写入方式保存数据和读取数据封装了两个方法:

封装的函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//保存游戏数据  
//参数介绍:
// (NSMutableArray *)data :保存的数据
// (NSString *)fileName :存储的文件名
-(BOOL) saveGameData:(NSMutableArray *)data saveFileName:(NSString *)fileName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(@"Documents directory not found!");
return NO;
}
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
return ([data writeToFile:appFile atomically:YES]);
}
//读取游戏数据
//参数介绍:
// (NSString *)fileName :需要读取数据的文件名
-(id) loadGameData:(NSString *)fileName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
NSMutableArray *myData = [[[NSMutableArray alloc] initWithContentsOfFile:appFile] autorelease];
return myData;
}

可以使用类似下面的例子进行使用

1
2
3
4
5
6
NSString *saveStr1 = @"测试保存读取";  
NSString *saveStr2 = @"两个函数";
NSMutableArray *array = [NSMutableArray arrayWithObjects:saveStr1, saveStr2, nil];
[self saveGameData:array saveFileName:@"Himi"];
NSMutableArray*temp =(NSMutableArray*)[self loadGameData:@"Himi"];
NSLog(@"%@--%@",[temp objectAtIndex:0],[temp objectAtIndex:1]);

有两点需要注意的地方:

1,取出数据的时候需要注意

1
2
NSUserDefaults *saveDefaults = [NSUserDefaults standardUserDefaults];   NSMutableArray *arraySaveData =[saveDefaults objectForKey:@"OhSaveData"];  
//NSMutableArray *arraySaveData=[NSMutableArray arrayWithArray:[saveDefaults objectForKey:@"OhSaveData"]];

第二句代码是通过一个文件名获取你存储的数据,返回数据数组,但是!一定要注意这里返回的数据数组是不可修改的!及时你将读取的数据赋给一个可修改的数组中也一样无法修改其中的数据,所以如果你想将取出的数据进行修改那么这里需要要使用第三行代码来获取

2,修改已经的存储文件

1
2
NSUserDefaults *saveDefaults = [NSUserDefaults standardUserDefaults];   
[saveDefaults setObject:arraySaveData forKey:@"已经存在的文件名"];

yii有个查询数据的便利的地方,就是可以在model层设置查询规则,然后在controller层,直接调用,进行数据查询:

举个例子说明一下:

先从model层说起:model名称叫做Blog,继承自CActiveRecord

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function scopes()
{
return [
'published' => [
'condition' => 'status=1',
],
'recently' => [
'order' => 'create_date DESC',
'limit' => 5,
],
'createDateDesc' => [
'order' => 'create_date DESC',
],
];
}

在上面的代码中,继承函数scopes,然后在里面命名自己想要使用的规则名称。

我这里使用了

published,recently,createCateDesc,分别对应sql语句的一部分,这个在调用controller的时候会合并到总的sql语句里面去的。

下面看在controller里面怎么使用

1
2
3
4
5
6
7
8
9
10
11
12
13
//最近的博文
$rawData = Blog::model()->recently()->findAll();
$rawData = new CArrayDataProvider($rawData, [
'sort' => [
'attributes' => [
'id',
'title',
],
],
'pagination' => [
'pageSize' => 10,
],
]);

我在自己的BlogController控制器,action为actionView的方法中引用了这样一个代码:

注意其中的recently部分

1
$rawData=Blog::model()->recently()->findAll();

这个就是我们在model层设置的规则,在这里作为方法被调用了。

是不是很方便呀。

详细的代码我贴到下面:

model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

<?php

/**
* This is the model class for table "tbl_blog".
*
* The followings are the available columns in table 'tbl_blog':
* @property integer $id
* @property string $title
* @property string $description
* @property string $create_date
* @property string $update_date
*/
class Blog extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* @param string $className active record class name.
* @return Blog the static model class
*/
public static function model($className = __CLASS__)
{
return parent::model($className);
}

/**
* @return string the associated database table name
*/
public function tableName()
{
return 'tbl_blog';
}

/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return [
['title', 'required', 'message' => '标题不能为空'],
['description', 'required', 'message' => '内容不能为空'],
['title', 'length', 'max' => 255],
['tag', 'safe'],
['type_id', 'safe'],
['update_date', 'safe'],
// The following rule is used by search().
// Please remove those attributes that should not be searched.
['id, title, description, create_date, update_date', 'safe', 'on' => 'search'],
];
}

/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return [
];
}

/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return [
'id' => 'ID序号',
'title' => '标题',
'description' => '内容',
'tag' => '标签(使用逗号进行分割)',
'type_id' => '分类类型',
'create_date' => '创建时间',
'update_date' => '更新时间',
];
}

/**
* Retrieves a list of models based on the current search/filter conditions.
* @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.

$criteria = new CDbCriteria();

$criteria->compare('id', $this->id);
$criteria->compare('title', $this->title, true);
$criteria->compare('description', $this->description, true);
$criteria->compare('create_date', $this->create_date, true);
$criteria->compare('update_date', $this->update_date, true);
$criteria->scopes = 'createDateDesc';
return new CActiveDataProvider($this, [
'criteria' => $criteria,
]);
}

/**
* 行为操作
*/
public function behaviors()
{
return [
'CTimestampBehavior' => [
'class' => 'zii.behaviors.CTimestampBehavior',
'createAttribute' => 'create_date',
'updateAttribute' => 'update_date',
'setUpdateOnCreate' => 'true',
],

];
}

//查询范围
public function scopes()
{
return [
'published' => [
'condition' => 'status=1',
],
'recently' => [
'order' => 'create_date DESC',
'limit' => 5,
],
'createDateDesc' => [
'order' => 'create_date DESC',
],
];
}
}
controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

<?php
class BlogController extends Controller
{
/**
* @var string the default layout for the views. Defaults to '//layouts/column2', meaning
* using two-column layout. See 'protected/views/layouts/column2.php'.
*/
public $layout = '//layouts/column2';

/**
* @return array action filters
*/
public function filters()
{
return [
'accessControl', // perform access control for CRUD operations
'postOnly + delete', // we only allow deletion via POST request
];
}

/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* @return array access control rules
*/
public function accessRules()
{
return [
['allow', // allow all users to perform 'index' and 'view' actions
'actions' => ['view'],
'users' => ['*'],
],
['allow', // allow authenticated user to perform 'create' and 'update' actions
'actions' => ['create', 'update', 'index'],
'users' => ['@'],
],
['allow', // allow admin user to perform 'admin' and 'delete' actions
'actions' => ['admin', 'delete'],
'user' => ['admin'],
],
['deny', // deny all users
'users' => ['*'],
],
];
}

/**
* Displays a particular model.
* @param integer $id the ID of the model to be displayed
*/
public function actionView($id)
{
//最近的博文
$rawData = Blog::model()->recently()->findAll();
$rawData = new CArrayDataProvider($rawData, [
'sort' => [
'attributes' => [
'id',
'title',

],
],
'pagination' => [
'pageSize' => 10,
],
]);

$recentBlogMenu = [];
foreach ($rawData->getData() as $key => $value) {
$recentBlogMenu[] = [
'label' => $value->title,
'url' => ['blog/view', 'id' => $value->id],
];
}

//博文的分类
$rawData = Type::model()->findAll();
$rawData = new CArrayDataProvider($rawData, [
'sort' => [
'attributes' => [
'id',
'name',
],
],
]);

$blogType = [];
foreach ($rawData->getData() as $key => $value) {
$blogType[] = [
'label' => $value->name,
'url' => ['type/search/' . $value->id],
];
}

$this->render('view', [
'model' => $this->loadModel($id),
'blogType' => $blogType,
'recentBlogMenu' => $recentBlogMenu,
]);
}

/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model = new Blog;

// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);

if (isset($_POST['Blog'])) {
$model->attributes = $_POST['Blog'];
if ($model->save()) {
$this->redirect(['view', 'id' => $model->id]);
}
}

$rawData = new CActiveDataProvider(
'Type',
[
'sort' => [
'attributes' => [
'id',
'name',

],
],
]
);

foreach ($rawData->getData() as $key => $value) {
$type[$value->id] = $value->name;
}

$this->render('create', [
'model' => $model,
'type' => $type,
]);
}

/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model = $this->loadModel($id);

// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);

if (isset($_POST['Blog'])) {
$model->attributes = $_POST['Blog'];
if ($model->save()) {
$this->redirect(['view', 'id' => $model->id]);
}
}

$rawData = new CActiveDataProvider(
'Type',
[
'sort' => [
'attributes' => [
'id',
'name',

],
],
]
);

foreach ($rawData->getData() as $key => $value) {
$type[$value->id] = $value->name;
}

$this->render('update', [
'model' => $model,
'type' => $type,
]);
}

/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'admin' page.
* @param integer $id the ID of the model to be deleted
*/
public function actionDelete($id)
{
$this->loadModel($id)->delete();

// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if (!isset($_GET['ajax'])) {
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : ['admin']);
}
}

/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider = new CActiveDataProvider(
'Blog',
[
'pagination' => ['pageSize' => 10],
'criteria' => [
'order' => 'create_date DESC',
],
]
);

$this->render('index', [
'dataProvider' => $dataProvider,
]);
}

/**
* Manages all models.
*/
public function actionAdmin()
{
$model = new Blog('search');
$model->unsetAttributes(); // clear any default values
if (isset($_GET['Blog'])) {
$model->attributes = $_GET['Blog'];
}

$this->render('admin', [
'model' => $model,
]);
}

/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
* @param integer the ID of the model to be loaded
*/
public function loadModel($id)
{
$model = Blog::model()->findByPk($id);
if (null === $model) {
throw new CHttpException(404, '请求的页面不存在.');
}

return $model;
}

/**
* Performs the AJAX validation.
* @param CModel the model to be validated
*/
protected function performAjaxValidation($model)
{
if (isset($_POST['ajax']) && 'blog-form' === $_POST['ajax']) {
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
}
0%